<commit_before>//----------------------------  make_dependencies.cc  ------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  make_dependencies.cc  ------------------------

// Make a dependency file tree
// usage: make_depencies -Iinc_path1 -Iinc_path2 ... -Bbasepath files

// This program is basically a replacement for something like "gcc
// -M", i.e. it egnerates for each input file a list of other files it
// depends on by direct or indirect inclusion (or at least those files
// that can be found in the directories specified by -I/path/.../
// flags on the command line). The difference to gcc -M is that it is
// much faster, since it doesn't really do much parsing except for
// finding those lines that have a #include at the beginning
//
// The output looks like this:
//
//   $basepath/.o-file $basepath/.g.o-file: file included_files
//
// $basepath is the dir where the object files are to be placed (as
// given by the -B parameter to this script)

// Author: Wolfgang Bangerth, 2003 (and based on a previous perl
// script written 1998, 1999, 2000, 2001, 2002)

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <cassert>

                                 // base path for object files
std::string basepath;

                                 // list of include directories
std::vector<std::string> include_directories;

                                 // for each file that we ever visit,
                                 // store the set of other files it
                                 // includes directly
std::map<std::string,std::set<std::string> > direct_includes;

                                 // for the given file, fill a
                                 // respective entry in the "direct_includes"
                                 // map listing the names of those
                                 // files that are directly included
void determine_direct_includes (const std::string &file)
{
                                   // if this file has already been
                                   // treated, then leave it at this
  if (direct_includes.find (file) != direct_includes.end())
    return;

                                   // otherwise, open the file and go
                                   // through it line by line to
                                   // search for other includes. we
                                   // will have to have the path to
                                   // the present file later, so get
                                   // it already here
  const std::string present_path (file.find ('/') != std::string::npos
                                  ?
                                  std::string (file.begin(),
                                               file.begin()+file.rfind ('/')+1)
                                  :
                                  "");
  std::ifstream in(file.c_str());
  assert (in);

  std::string line;
  while (in)
    {
                                       // get one line, eat whitespace
                                       // at the beginning and see
                                       // whether the first
                                       // non-whitespace is a #
                                       // character
      getline (in, line);
      unsigned int pos=0;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // if no non-whitespace, or
                                       // something other than #: next
                                       // line
      if ((pos == line.length()) || (line[pos] != '#'))
        continue;

                                       // ok, this is a preprocessor
                                       // line. eat pound sign and
                                       // again the next couple of
                                       // whitespaces
      ++pos;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // and let's see whether the
                                       // following is the word
                                       // include
      if ((line.length() < pos+7)
          ||
          (! ((line[pos+0] == 'i') &&
              (line[pos+1] == 'n') &&
              (line[pos+2] == 'c') &&
              (line[pos+3] == 'l') &&
              (line[pos+4] == 'u') &&
              (line[pos+5] == 'd') &&
              (line[pos+6] == 'e'))))
        continue;

                                       // ok, word found. advance pos
                                       // and eat more whitespace
      pos += 7;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // check that the next char is
                                       // either '<' or '"'
      if ((line[pos] != '"') && (line[pos] != '<'))
        continue;

                                       // copy out name
      std::string included_file;
      for (unsigned int endpos=pos+1; endpos<line.length(); ++endpos)
        if ((line[endpos]=='"') || (line[endpos] == '>'))
          {
            included_file = std::string (line.begin()+pos+1,
                                         line.begin()+endpos);
            break;
          }
      assert (included_file.length() > 0);

                                       // next try to locate the file
                                       // in absolute paths. this is
                                       // easy if it was included via
                                       // "...", but for <...> we have
                                       // to work a little harder
      if (included_file[0] != '/')
        {
          if (line[pos] == '"')
            included_file = present_path+included_file;
          else
            for (std::vector<std::string>::const_iterator
                   include_dir=include_directories.begin();
                 include_dir!=include_directories.end(); ++include_dir)
              if (std::ifstream((*include_dir+included_file).c_str()))
                {
                  included_file = *include_dir+included_file;
                  break;
                }
        }

                                       // make sure the file
                                       // exists, otherwise just
                                       // ignore the line
      if (!std::ifstream(included_file.c_str()))
        continue;

                                       // ok, so we did find an
                                       // appropriate file. add it to
                                       // the correct list
      direct_includes[file].insert (included_file);

                                       // work on the include file
                                       // recursively. note that the
                                       // first line of this file
                                       // saves us from infinite
                                       // recursions in case of
                                       // include loops
      determine_direct_includes (included_file);
    }
}

                                 // return the set of all included
                                 // files, directly or indirectly, for
                                 // the given file. for this purpose,
                                 // we consider the direct_includes
                                 // variable to be a representation of
                                 // a directed graph: given a file (a
                                 // node in the graph), the elements
                                 // of the include-set for this file
                                 // are outgoing edges from this
                                 // node. to get at all includes,
                                 // direct and indirect, we keep a
                                 // list starting with the direct
                                 // includes, the collect all direct
                                 // includes of the files in the list,
                                 // then their include files, etc. We
                                 // thus march in fronts through the
                                 // graph.
                                 //
                                 // one of the complications we have
                                 // to keep track of is that the graph
                                 // may be cyclic (i.e. header files
                                 // include each other mutually -- in
                                 // the real program, one of the
                                 // includes will be guarded by
                                 // preprocessor #ifdefs, but we don't
                                 // see them here), so we have to make
                                 // sure we strip elements from the
                                 // present front that we have already
                                 // visited before
                                 //
                                 // this function could presumably be
                                 // made more efficient in the
                                 // following way: when we have more
                                 // than one file for which we want to
                                 // compute dependencies, we presently
                                 // walk through the graph for each of
                                 // them. however, they will likely
                                 // have one or more includes in
                                 // common, so they will also have
                                 // parts of the dependency graph in
                                 // common. if we could precompute the
                                 // dependency graph for include files
                                 // in advance, we wouldn't have to
                                 // walk through _all_ the graph for
                                 // each file we consider, but could
                                 // just draw in blocks. the problem
                                 // with that is that to make this
                                 // efficient we cannot just compute
                                 // the whole set of dependencies for
                                 // _each_ file, but we have to do
                                 // this on the fly and to avoid again
                                 // problems with the cyclic nature we
                                 // have to keep track where we are
                                 // presently coming from. that's way
                                 // too complicated for now and I
                                 // leave it to times when dependency
                                 // generation becomes again a
                                 // noticable time hit
                                 //
                                 // one of the ideas to solve this
                                 // problem would be to start at
                                 // terminal nodes of the graph
                                 // (i.e. nodes that have no outgoing
                                 // edges) and fold these nodes into
                                 // nodes that have only outgoing
                                 // edges to terminal nodes. store the
                                 // dependencies of these
                                 // next-to-terminal nodes and remove
                                 // the terminal ones. then start over
                                 // again with the so generated
                                 // graph. if we consider the files
                                 // for which we want to compute
                                 // dependency information as top
                                 // level nodes (they will _only_ have
                                 // outgoing nodes), we could
                                 // presumable roll up the entire
                                 // graph from the bottom (terminal
                                 // nodes) and fold it one layer at a
                                 // time
                                 //
                                 // in any case, there is presently no
                                 // need for this since the actions of
                                 // this function are presently not
                                 // really time critical: parsing the
                                 // files in the function above is a
                                 // much bigger time-hit.
std::set<std::string>
get_all_includes (const std::string &name)
{
                                   // start with direct includes
  std::set<std::string> all_includes = direct_includes[name];

  std::set<std::string> next_level_includes = all_includes;
  while (true)
    {
                                       // traverse all next level
                                       // includes and get their
                                       // direct include files. the
                                       // set makes sure that
                                       // duplicates are removed
      std::set<std::string> second_next;
      for (std::set<std::string>::const_iterator
             next=next_level_includes.begin();
           next!=next_level_includes.end(); ++next)
        second_next.insert (direct_includes[*next].begin(),
                            direct_includes[*next].end());

                                       // for each of them, if it
                                       // hasn't been treated then add
                                       // it to the files of the next
                                       // level and later add it to
                                       // the all_includes
      next_level_includes.clear ();
      for (std::set<std::string>::const_iterator f=second_next.begin();
           f!=second_next.end(); ++f)
        if (all_includes.find(*f) == all_includes.end())
          next_level_includes.insert (*f);

                                       // if no new includes found no
                                       // more, then quit
      if (next_level_includes.size() == 0)
        return all_includes;

                                       // otherwise, copy over and
                                       // start over on the next level
                                       // of the tree
      all_includes.insert (next_level_includes.begin(),
                           next_level_includes.end());
    }
}

int main (int argc, char **argv)
{
  std::vector<std::string> filenames;

                                   // parse all arguments (except the
                                   // name of the executable itself)
  for (unsigned int c=1; c<argc; ++c)
    {
      const std::string arg = argv[c];

                                       // if string starts with -I,
                                       // take this as an include path
      if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='I'))
        {
          std::string dir (arg.begin()+2, arg.end());

                                           // append a slash if not
                                           // already there
          if (dir[dir.length()-1] != '/')
            dir += '/';

                                           // drop initial ./ if this
                                           // is there
          if ((dir[0]=='.') && (dir[1]=='/'))
            dir = std::string(dir.begin()+2, dir.end());

          include_directories.push_back (dir);
        }
                                       // if string starts with -B,
                                       // then this is the base name
                                       // for object files
      else if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='B'))
        basepath = std::string(arg.begin()+2, arg.end());

                                       // otherwise assume that this
                                       // is one of the files for
                                       // input
      else
        {
          assert (arg.size()>=1);
          assert (arg[0] != '-');

          filenames.push_back (arg);
        }
    }

                                   // next iterate through all files
                                   // and figure out which other files
                                   // they include
  for (std::vector<std::string>::const_iterator file=filenames.begin();
       file != filenames.end(); ++file)
    determine_direct_includes (*file);

                                   // now we have all files that are
                                   // directly or indirectly included
                                   // into the files given on the
                                   // command lines. for each of them,
                                   // we have recorded which files
                                   // they include themselves. for
                                   // each file on the command line,
                                   // we can thus form a complete
                                   // include tree.
  for (std::vector<std::string>::const_iterator file=filenames.begin();
       file != filenames.end(); ++file)
    {
                                       // get base of filename by
                                       // chipping away .cc extension
                                       // as well as path
      std::string basename;
      if (file->find (".cc") != std::string::npos)
        basename = std::string (file->begin(),
                                file->begin()+file->find (".cc"));
      else if (file->find (".cpp") != std::string::npos)
        basename = std::string (file->begin(),
                                file->begin()+file->find (".cpp"));
      else
        basename = *file;

      if (basename.rfind ("/") != std::string::npos)
        basename = std::string (basename.begin()+basename.rfind("/")+1,
                                basename.end());

      std::cout << basepath << "/" << basename << ".o "
                << basepath << "/" << basename << ".g.o: \\"
                << std::endl
                << "\t\t" << *file;

      const std::set<std::string> includes = get_all_includes (*file);
      for (std::set<std::string>::const_iterator i=includes.begin();
           i!=includes.end(); ++i)
        std::cout << "\\\n\t\t" << *i;
      std::cout << std::endl;
    }
}

<commit_msg>Write out separate dependcy lists for .o and .g.o so as to not confuse the Makefile in the deal.II subdir.<commit_after>//----------------------------  make_dependencies.cc  ------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  make_dependencies.cc  ------------------------

// Make a dependency file tree
// usage: make_depencies -Iinc_path1 -Iinc_path2 ... -Bbasepath files

// This program is basically a replacement for something like "gcc
// -M", i.e. it egnerates for each input file a list of other files it
// depends on by direct or indirect inclusion (or at least those files
// that can be found in the directories specified by -I/path/.../
// flags on the command line). The difference to gcc -M is that it is
// much faster, since it doesn't really do much parsing except for
// finding those lines that have a #include at the beginning
//
// The output looks like this:
//
//   $basepath/.o-file $basepath/.g.o-file: file included_files
//
// $basepath is the dir where the object files are to be placed (as
// given by the -B parameter to this script)

// Author: Wolfgang Bangerth, 2003 (and based on a previous perl
// script written 1998, 1999, 2000, 2001, 2002)

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <cassert>

                                 // base path for object files
std::string basepath;

                                 // list of include directories
std::vector<std::string> include_directories;

                                 // for each file that we ever visit,
                                 // store the set of other files it
                                 // includes directly
std::map<std::string,std::set<std::string> > direct_includes;

                                 // for the given file, fill a
                                 // respective entry in the "direct_includes"
                                 // map listing the names of those
                                 // files that are directly included
void determine_direct_includes (const std::string &file)
{
                                   // if this file has already been
                                   // treated, then leave it at this
  if (direct_includes.find (file) != direct_includes.end())
    return;

                                   // otherwise, open the file and go
                                   // through it line by line to
                                   // search for other includes. we
                                   // will have to have the path to
                                   // the present file later, so get
                                   // it already here
  const std::string present_path (file.find ('/') != std::string::npos
                                  ?
                                  std::string (file.begin(),
                                               file.begin()+file.rfind ('/')+1)
                                  :
                                  "");
  std::ifstream in(file.c_str());
  assert (in);

  std::string line;
  while (in)
    {
                                       // get one line, eat whitespace
                                       // at the beginning and see
                                       // whether the first
                                       // non-whitespace is a #
                                       // character
      getline (in, line);
      unsigned int pos=0;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // if no non-whitespace, or
                                       // something other than #: next
                                       // line
      if ((pos == line.length()) || (line[pos] != '#'))
        continue;

                                       // ok, this is a preprocessor
                                       // line. eat pound sign and
                                       // again the next couple of
                                       // whitespaces
      ++pos;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // and let's see whether the
                                       // following is the word
                                       // include
      if ((line.length() < pos+7)
          ||
          (! ((line[pos+0] == 'i') &&
              (line[pos+1] == 'n') &&
              (line[pos+2] == 'c') &&
              (line[pos+3] == 'l') &&
              (line[pos+4] == 'u') &&
              (line[pos+5] == 'd') &&
              (line[pos+6] == 'e'))))
        continue;

                                       // ok, word found. advance pos
                                       // and eat more whitespace
      pos += 7;
      for (; pos<line.length(); ++pos)
        if ((line[pos] != ' ') && (line[pos] != '\t'))
          break;

                                       // check that the next char is
                                       // either '<' or '"'
      if ((line[pos] != '"') && (line[pos] != '<'))
        continue;

                                       // copy out name
      std::string included_file;
      for (unsigned int endpos=pos+1; endpos<line.length(); ++endpos)
        if ((line[endpos]=='"') || (line[endpos] == '>'))
          {
            included_file = std::string (line.begin()+pos+1,
                                         line.begin()+endpos);
            break;
          }
      assert (included_file.length() > 0);

                                       // next try to locate the file
                                       // in absolute paths. this is
                                       // easy if it was included via
                                       // "...", but for <...> we have
                                       // to work a little harder
      if (included_file[0] != '/')
        {
          if (line[pos] == '"')
            included_file = present_path+included_file;
          else
            for (std::vector<std::string>::const_iterator
                   include_dir=include_directories.begin();
                 include_dir!=include_directories.end(); ++include_dir)
              if (std::ifstream((*include_dir+included_file).c_str()))
                {
                  included_file = *include_dir+included_file;
                  break;
                }
        }

                                       // make sure the file
                                       // exists, otherwise just
                                       // ignore the line
      if (!std::ifstream(included_file.c_str()))
        continue;

                                       // ok, so we did find an
                                       // appropriate file. add it to
                                       // the correct list
      direct_includes[file].insert (included_file);

                                       // work on the include file
                                       // recursively. note that the
                                       // first line of this file
                                       // saves us from infinite
                                       // recursions in case of
                                       // include loops
      determine_direct_includes (included_file);
    }
}

                                 // return the set of all included
                                 // files, directly or indirectly, for
                                 // the given file. for this purpose,
                                 // we consider the direct_includes
                                 // variable to be a representation of
                                 // a directed graph: given a file (a
                                 // node in the graph), the elements
                                 // of the include-set for this file
                                 // are outgoing edges from this
                                 // node. to get at all includes,
                                 // direct and indirect, we keep a
                                 // list starting with the direct
                                 // includes, the collect all direct
                                 // includes of the files in the list,
                                 // then their include files, etc. We
                                 // thus march in fronts through the
                                 // graph.
                                 //
                                 // one of the complications we have
                                 // to keep track of is that the graph
                                 // may be cyclic (i.e. header files
                                 // include each other mutually -- in
                                 // the real program, one of the
                                 // includes will be guarded by
                                 // preprocessor #ifdefs, but we don't
                                 // see them here), so we have to make
                                 // sure we strip elements from the
                                 // present front that we have already
                                 // visited before
                                 //
                                 // this function could presumably be
                                 // made more efficient in the
                                 // following way: when we have more
                                 // than one file for which we want to
                                 // compute dependencies, we presently
                                 // walk through the graph for each of
                                 // them. however, they will likely
                                 // have one or more includes in
                                 // common, so they will also have
                                 // parts of the dependency graph in
                                 // common. if we could precompute the
                                 // dependency graph for include files
                                 // in advance, we wouldn't have to
                                 // walk through _all_ the graph for
                                 // each file we consider, but could
                                 // just draw in blocks. the problem
                                 // with that is that to make this
                                 // efficient we cannot just compute
                                 // the whole set of dependencies for
                                 // _each_ file, but we have to do
                                 // this on the fly and to avoid again
                                 // problems with the cyclic nature we
                                 // have to keep track where we are
                                 // presently coming from. that's way
                                 // too complicated for now and I
                                 // leave it to times when dependency
                                 // generation becomes again a
                                 // noticable time hit
                                 //
                                 // one of the ideas to solve this
                                 // problem would be to start at
                                 // terminal nodes of the graph
                                 // (i.e. nodes that have no outgoing
                                 // edges) and fold these nodes into
                                 // nodes that have only outgoing
                                 // edges to terminal nodes. store the
                                 // dependencies of these
                                 // next-to-terminal nodes and remove
                                 // the terminal ones. then start over
                                 // again with the so generated
                                 // graph. if we consider the files
                                 // for which we want to compute
                                 // dependency information as top
                                 // level nodes (they will _only_ have
                                 // outgoing nodes), we could
                                 // presumable roll up the entire
                                 // graph from the bottom (terminal
                                 // nodes) and fold it one layer at a
                                 // time
                                 //
                                 // in any case, there is presently no
                                 // need for this since the actions of
                                 // this function are presently not
                                 // really time critical: parsing the
                                 // files in the function above is a
                                 // much bigger time-hit.
std::set<std::string>
get_all_includes (const std::string &name)
{
                                   // start with direct includes
  std::set<std::string> all_includes = direct_includes[name];

  std::set<std::string> next_level_includes = all_includes;
  while (true)
    {
                                       // traverse all next level
                                       // includes and get their
                                       // direct include files. the
                                       // set makes sure that
                                       // duplicates are removed
      std::set<std::string> second_next;
      for (std::set<std::string>::const_iterator
             next=next_level_includes.begin();
           next!=next_level_includes.end(); ++next)
        second_next.insert (direct_includes[*next].begin(),
                            direct_includes[*next].end());

                                       // for each of them, if it
                                       // hasn't been treated then add
                                       // it to the files of the next
                                       // level and later add it to
                                       // the all_includes
      next_level_includes.clear ();
      for (std::set<std::string>::const_iterator f=second_next.begin();
           f!=second_next.end(); ++f)
        if (all_includes.find(*f) == all_includes.end())
          next_level_includes.insert (*f);

                                       // if no new includes found no
                                       // more, then quit
      if (next_level_includes.size() == 0)
        return all_includes;

                                       // otherwise, copy over and
                                       // start over on the next level
                                       // of the tree
      all_includes.insert (next_level_includes.begin(),
                           next_level_includes.end());
    }
}

int main (int argc, char **argv)
{
  std::vector<std::string> filenames;

                                   // parse all arguments (except the
                                   // name of the executable itself)
  for (unsigned int c=1; c<argc; ++c)
    {
      const std::string arg = argv[c];

                                       // if string starts with -I,
                                       // take this as an include path
      if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='I'))
        {
          std::string dir (arg.begin()+2, arg.end());

                                           // append a slash if not
                                           // already there
          if (dir[dir.length()-1] != '/')
            dir += '/';

                                           // drop initial ./ if this
                                           // is there
          if ((dir[0]=='.') && (dir[1]=='/'))
            dir = std::string(dir.begin()+2, dir.end());

          include_directories.push_back (dir);
        }
                                       // if string starts with -B,
                                       // then this is the base name
                                       // for object files
      else if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='B'))
        basepath = std::string(arg.begin()+2, arg.end());

                                       // otherwise assume that this
                                       // is one of the files for
                                       // input
      else
        {
          assert (arg.size()>=1);
          assert (arg[0] != '-');

          filenames.push_back (arg);
        }
    }

                                   // next iterate through all files
                                   // and figure out which other files
                                   // they include
  for (std::vector<std::string>::const_iterator file=filenames.begin();
       file != filenames.end(); ++file)
    determine_direct_includes (*file);

                                   // now we have all files that are
                                   // directly or indirectly included
                                   // into the files given on the
                                   // command lines. for each of them,
                                   // we have recorded which files
                                   // they include themselves. for
                                   // each file on the command line,
                                   // we can thus form a complete
                                   // include tree.
  for (std::vector<std::string>::const_iterator file=filenames.begin();
       file != filenames.end(); ++file)
    {
                                       // get base of filename by
                                       // chipping away .cc extension
                                       // as well as path
      std::string basename;
      if (file->find (".cc") != std::string::npos)
        basename = std::string (file->begin(),
                                file->begin()+file->find (".cc"));
      else if (file->find (".cpp") != std::string::npos)
        basename = std::string (file->begin(),
                                file->begin()+file->find (".cpp"));
      else
        basename = *file;

      if (basename.rfind ("/") != std::string::npos)
        basename = std::string (basename.begin()+basename.rfind("/")+1,
                                basename.end());

      std::cout << basepath << "/" << basename << ".o: \\"
                << std::endl
                << "\t\t" << *file;

      const std::set<std::string> includes = get_all_includes (*file);

      for (std::set<std::string>::const_iterator i=includes.begin();
           i!=includes.end(); ++i)
        std::cout << "\\\n\t\t" << *i;
      std::cout << std::endl;

      std::cout << basepath << "/" << basename << ".g.o: \\"
                << std::endl
                << "\t\t" << *file;

      for (std::set<std::string>::const_iterator i=includes.begin();
           i!=includes.end(); ++i)
        std::cout << "\\\n\t\t" << *i;
      std::cout << std::endl;
    }
}

<|endoftext|>


<commit_before>/*
   Copyright (c) 2009-2012, Jack Poulson
   All rights reserved.

   This file is part of Elemental.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

    - Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    - Neither the name of the owner nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
*/
#include "elemental.hpp"
using namespace std;
using namespace elem;

// Typedef our real and complex types to 'R' and 'C' for convenience
typedef double R;
typedef Complex<R> C;

void Usage()
{
    cout << "SVD <m> <n>\n"
         << "  <m>: height of random matrix to test SVD on\n"
         << "  <n>: width of random matrix to test SVD on\n"
         << endl;
}

int
main( int argc, char* argv[] )
{
    Initialize( argc, argv );

    mpi::Comm comm = mpi::COMM_WORLD;
    const int commRank = mpi::CommRank( comm );

    if( argc < 3 )
    {
        if( commRank == 0 )
            Usage();
        Finalize();
        return 0;
    }
    const int m = atoi( argv[1] );
    const int n = atoi( argv[2] );

    try
    {
        Grid g( comm );
        DistMatrix<C,MC,MR> A( g );
        Uniform( m, n, A );

        // Compute the SVD of A (but do not overwrite A)
        DistMatrix<C,MC,MR> U( g );
        DistMatrix<C,MC,MR> V( g );
        DistMatrix<R,VR,STAR> s( g );
        U = A;
        SVD( U, s, V );

        // This is a bit of a hack since norms are not supported for anything
        // but [MC,MR] distributions (as of yet)
        DistMatrix<R,MC,MR> s_MC_MR( s );
        const R twoNormOfA = Norm( s_MC_MR, MAX_NORM );

        const R oneNormOfA = Norm( A, ONE_NORM );
        const R frobNormOfA = Norm( A, FROBENIUS_NORM );
        DiagonalScale( RIGHT, NORMAL, s, U );
        Gemm( NORMAL, ADJOINT, (C)-1, U, V, (C)1, A );
        const R oneNormOfE = Norm( A, ONE_NORM );
        const R frobNormOfE = Norm( A, FROBENIUS_NORM );
        const R epsilon = lapack::MachineEpsilon<R>();
        const R scaledResidual = frobNormOfE / (max(m,n)*epsilon*twoNormOfA);

        if( commRank == 0 )
        {
            cout << "||A||_1 = " << oneNormOfA << "\n"
                 << "||A||_2 = " << twoNormOfA << "\n"
                 << "||A||_F = " << frobNormOfA << "\n"
                 << "||A - U Sigma V^H||_1 = " << oneNormOfE << "\n"
                 << "||A - U Sigma V^H||_F = " << frobNormOfE << "\n"
                 << "||A - U Sigma V_H||_F / (max(m,n) eps ||A||_2) = "
                 << scaledResidual << "\n" << endl;
        }
    }
    catch( exception& e )
    {
        cerr << "Process " << commRank << " caught exception with message: "
             << e.what() << endl;
#ifndef RELEASE
        DumpCallStack();
#endif
    }

    Finalize();
    return 0;
}

<commit_msg>Slightly tweaking the SVD example driver.<commit_after>/*
   Copyright (c) 2009-2012, Jack Poulson
   All rights reserved.

   This file is part of Elemental.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

    - Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    - Neither the name of the owner nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
*/
#include "elemental.hpp"
using namespace std;
using namespace elem;

// Typedef our real and complex types to 'R' and 'C' for convenience
typedef double R;
typedef Complex<R> C;

void Usage()
{
    cout << "SVD <m> <n>\n"
         << "  <m>: height of random matrix to test SVD on\n"
         << "  <n>: width of random matrix to test SVD on\n"
         << endl;
}

int
main( int argc, char* argv[] )
{
    Initialize( argc, argv );

    mpi::Comm comm = mpi::COMM_WORLD;
    const int commRank = mpi::CommRank( comm );

    if( argc < 3 )
    {
        if( commRank == 0 )
            Usage();
        Finalize();
        return 0;
    }
    const int m = atoi( argv[1] );
    const int n = atoi( argv[2] );

    try
    {
        Grid g( comm );
        DistMatrix<C,MC,MR> A( g );
        Uniform( m, n, A );

        // Compute the SVD of A (but do not overwrite A)
        DistMatrix<C,MC,MR> U( g );
        DistMatrix<C,MC,MR> V( g );
        DistMatrix<R,VR,STAR> s( g );
        U = A;
        SVD( U, s, V );

        // This is a bit of a hack since norms are not supported for anything
        // but [MC,MR] distributions (as of yet)
        DistMatrix<R,MC,MR> s_MC_MR( s );
        const R twoNormOfA = Norm( s_MC_MR, MAX_NORM );

        // Combine various cheap bounds on the two-norm of A:
        //             ||A||_max \le ||A||_2,
        //   1/sqrt(n) ||A||_oo  \le ||A||_2,
        //   1/sqrt(m) ||A||_1   \le ||A||_2,
        //   1/sqrt(k) ||A||_F   \le ||A||_2.
        //
        //   ||A||_2 \le \sqrt(m n) ||A||_max,
        //   ||A||_2 \le \sqrt(m)   ||A||_oo,
        //   ||A||_2 \le \sqrt(n)   ||A||_1,
        //   ||A||_2 \le \sqrt( ||A||_1 ||A||_oo ).
        //
        const R maxNormOfA = Norm( A, MAX_NORM );
        const R oneNormOfA = Norm( A, ONE_NORM );
        const R infNormOfA = Norm( A, INFINITY_NORM );
        const R frobNormOfA = Norm( A, FROBENIUS_NORM );
        R lowerBound = std::max( maxNormOfA, infNormOfA/sqrt(n) );
        lowerBound = std::max( lowerBound, oneNormOfA/sqrt(m) );
        lowerBound = std::max( lowerBound, frobNormOfA/sqrt(min(m,n)) );
        R upperBound = std::min( sqrt(m*n)*maxNormOfA, sqrt(m)*infNormOfA );
        upperBound = std::min( upperBound, sqrt(n)*oneNormOfA );
        upperBound = std::min( upperBound, sqrt( oneNormOfA*infNormOfA ) );

        DiagonalScale( RIGHT, NORMAL, s, U );
        Gemm( NORMAL, ADJOINT, (C)-1, U, V, (C)1, A );
        const R maxNormOfE = Norm( A, MAX_NORM );
        const R oneNormOfE = Norm( A, ONE_NORM );
        const R infNormOfE = Norm( A, INFINITY_NORM );
        const R frobNormOfE = Norm( A, FROBENIUS_NORM );
        const R epsilon = lapack::MachineEpsilon<R>();
        const R scaledResidual = frobNormOfE / (max(m,n)*epsilon*twoNormOfA);

        if( commRank == 0 )
        {
            cout << "||A||_max   = " << maxNormOfA << "\n"
                 << "||A||_1     = " << oneNormOfA << "\n"
                 << "||A||_oo    = " << infNormOfA << "\n"
                 << "||A||_F     = " << frobNormOfA << "\n"
                 << "\n"
                 << "lower bound = " << lowerBound << "\n"
                 << "||A||_2     = " << twoNormOfA << "\n"
                 << "upper bound = " << upperBound << "\n"
                 << "\n"
                 << "||A - U Sigma V^H||_max = " << maxNormOfE << "\n"
                 << "||A - U Sigma V^H||_1   = " << oneNormOfE << "\n"
                 << "||A - U Sigma V^H||_oo  = " << infNormOfE << "\n"
                 << "||A - U Sigma V^H||_F   = " << frobNormOfE << "\n"
                 << "||A - U Sigma V_H||_F / (max(m,n) eps ||A||_2) = "
                 << scaledResidual << "\n" << endl;
        }
    }
    catch( exception& e )
    {
        cerr << "Process " << commRank << " caught exception with message: "
             << e.what() << endl;
#ifndef RELEASE
        DumpCallStack();
#endif
    }

    Finalize();
    return 0;
}

<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalJIT.h"

#include "IncrementalExecutor.h"

#include "llvm/Support/DynamicLibrary.h"

using namespace llvm;

namespace {
// Forward cxa_atexit for global d'tors.
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
  cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
  exe->AddAtExitFunc(func, arg);
}

///\brief Memory manager providing the lop-level link to the
/// IncrementalExecutor, handles missing or special / replaced symbols.
class ClingMemoryManager: public SectionMemoryManager {
  cling::IncrementalExecutor& m_exe;

public:
  ClingMemoryManager(cling::IncrementalExecutor& Exe):
    m_exe(Exe) {}

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
  }

  ///\brief Simply wraps the base class's function setting AbortOnFailure
  /// to false and instead using the error handling mechanism to report it.
  void* getPointerToNamedFunction(const std::string &Name,
                                  bool /*AbortOnFailure*/ =true) override {
    return SectionMemoryManager::getPointerToNamedFunction(Name, false);
  }
};
} // unnamed namespace

namespace cling {

///\brief Memory manager for the OrcJIT layers to resolve symbols from the
/// common IncrementalJIT. I.e. the master of the Orcs.
/// Each ObjectLayer instance has one Azog object.
class Azog: public RTDyldMemoryManager {
  cling::IncrementalJIT& m_jit;

public:
  Azog(cling::IncrementalJIT& Jit): m_jit(Jit) {}

  RTDyldMemoryManager* getExeMM() const { return m_jit.m_ExeMM.get(); }

  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID,
                               StringRef SectionName) override {
    uint8_t *Addr =
      getExeMM()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID, StringRef SectionName,
                               bool IsReadOnly) override {
    uint8_t *Addr = getExeMM()->allocateDataSection(Size, Alignment, SectionID,
                                                    SectionName, IsReadOnly);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
                              uintptr_t DataSizeRW) override {
    return getExeMM()->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
  }

  bool needsToReserveAllocationSpace() override {
    return getExeMM()->needsToReserveAllocationSpace();
  }

  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                        size_t Size) override {
    return getExeMM()->registerEHFrames(Addr, LoadAddr, Size);
  }

  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                          size_t Size) override {
    return getExeMM()->deregisterEHFrames(Addr, LoadAddr, Size);
  }

  uint64_t getSymbolAddress(const std::string &Name) override {
    return m_jit.getSymbolAddressWithoutMangling(Name);
  }

  void *getPointerToNamedFunction(const std::string &Name,
                                  bool AbortOnFailure = true) override {
    return getExeMM()->getPointerToNamedFunction(Name, AbortOnFailure);
  }

  void notifyObjectLoaded(ExecutionEngine *EE,
                          const object::ObjectFile &O) override {
    return getExeMM()->notifyObjectLoaded(EE, O);
  }

  bool finalizeMemory(std::string *ErrMsg = nullptr) override {
    // Each set of objects loaded will be finalized exactly once, but since
    // symbol lookup during relocation may recursively trigger the
    // loading/relocation of other modules, and since we're forwarding all
    // finalizeMemory calls to a single underlying memory manager, we need to
    // defer forwarding the call on until all necessary objects have been
    // loaded. Otherwise, during the relocation of a leaf object, we will end
    // up finalizing memory, causing a crash further up the stack when we
    // attempt to apply relocations to finalized memory.
    // To avoid finalizing too early, look at how many objects have been
    // loaded but not yet finalized. This is a bit of a hack that relies on
    // the fact that we're lazily emitting object files: The only way you can
    // get more than one set of objects loaded but not yet finalized is if
    // they were loaded during relocation of another set.
    if (m_jit.m_UnfinalizedSections.size() == 1)
      return getExeMM()->finalizeMemory(ErrMsg);
    return false;
  };

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(Name);
  }

}; // class Azog

IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe,
                               std::unique_ptr<TargetMachine> TM):
  m_Parent(exe),
  m_TM(std::move(TM)),
  m_ExeMM(std::move(llvm::make_unique<ClingMemoryManager>(m_Parent))),
  m_Mang(m_TM->getDataLayout()),
  m_NotifyObjectLoaded(*this), m_NotifyFinalized(*this),
  m_ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), m_NotifyObjectLoaded,
                m_NotifyFinalized),
  m_CompileLayer(m_ObjectLayer, SimpleCompiler(*m_TM)),
  m_LazyEmitLayer(m_CompileLayer) {

  // Enable JIT symbol resolution from the binary.
  llvm::sys::DynamicLibrary::LoadLibraryPermanently(0, 0);

// #if MCJIT
//   llvm::EngineBuilder builder(std::move(m));

//   std::string errMsg;
//   builder.setErrorStr(&errMsg);
//   builder.setOptLevel(llvm::CodeGenOpt::Less);
//   builder.setEngineKind(llvm::EngineKind::JIT);
//   std::unique_ptr<llvm::RTDyldMemoryManager>
//     MemMan(new ClingMemoryManager(*this));
//   builder.setMCJITMemoryManager(std::move(MemMan));

//   // EngineBuilder uses default c'ted TargetOptions, too:
//   llvm::TargetOptions TargetOpts;
//   TargetOpts.NoFramePointerElim = 1;
//   TargetOpts.JITEmitDebugInfo = 1;

//   builder.setTargetOptions(TargetOpts);

//   m_engine.reset(builder.create());
//   assert(m_engine && "Cannot create module!");
// #endif
}

uint64_t IncrementalJIT::getSymbolAddressWithoutMangling(llvm::StringRef Name) {
#ifdef __APPLE__
  // Apple adds an extra '_'
# define MANGLE_PREFIX "_"
#else
# define MANGLE_PREFIX ""
#endif
  if (Name == MANGLE_PREFIX "__cxa_atexit") {
    // Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
    // coming from the JIT.
    return (uint64_t)&local_cxa_atexit;
  } else if (Name == MANGLE_PREFIX "__dso_handle") {
    // Provide IncrementalExecutor as the third argument to __cxa_atexit.
    return (uint64_t)&m_Parent;
  }
#undef MANGLE_PREFIX
  if (uint64_t Addr = m_ExeMM->getSymbolAddress(Name))
    return Addr;
  if (uint64_t Addr = m_LazyEmitLayer.getSymbolAddress(Name, false))
    return Addr;

  return 0;
}

size_t IncrementalJIT::addModules(std::vector<llvm::Module*>&& modules) {
  // If this module doesn't have a DataLayout attached then attach the
  // default.
  for (auto&& mod: modules) {
    if (!mod->getDataLayout())
      mod->setDataLayout(m_TM->getDataLayout());
  }

  ModuleSetHandleT MSHandle
    = m_LazyEmitLayer.addModuleSet(std::move(modules),
                                   llvm::make_unique<Azog>(*this));
  m_UnloadPoints.push_back(MSHandle);
  return m_UnloadPoints.size() - 1;
}

// void* IncrementalJIT::finalizeMemory() {
//   for (auto &P : UnfinalizedSections)
//     if (P.second.count(LocalAddress))
//       ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress);
// }

void IncrementalJIT::removeModules(size_t handle) {
  m_LazyEmitLayer.removeModuleSet(m_UnloadPoints[handle]);
}

}// end namespace cling
<commit_msg>Also symbol lookup needs to remove the leading "_" on MacOS.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalJIT.h"

#include "IncrementalExecutor.h"

#include "llvm/Support/DynamicLibrary.h"

#ifdef __APPLE__
// Apple adds an extra '_'
# define MANGLE_PREFIX "_"
#else
# define MANGLE_PREFIX ""
#endif

using namespace llvm;

namespace {
// Forward cxa_atexit for global d'tors.
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
  cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
  exe->AddAtExitFunc(func, arg);
}

///\brief Memory manager providing the lop-level link to the
/// IncrementalExecutor, handles missing or special / replaced symbols.
class ClingMemoryManager: public SectionMemoryManager {
  cling::IncrementalExecutor& m_exe;

public:
  ClingMemoryManager(cling::IncrementalExecutor& Exe):
    m_exe(Exe) {}

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
  }

  ///\brief Simply wraps the base class's function setting AbortOnFailure
  /// to false and instead using the error handling mechanism to report it.
  void* getPointerToNamedFunction(const std::string &Name,
                                  bool /*AbortOnFailure*/ =true) override {
    return SectionMemoryManager::getPointerToNamedFunction(Name, false);
  }
};
} // unnamed namespace

namespace cling {

///\brief Memory manager for the OrcJIT layers to resolve symbols from the
/// common IncrementalJIT. I.e. the master of the Orcs.
/// Each ObjectLayer instance has one Azog object.
class Azog: public RTDyldMemoryManager {
  cling::IncrementalJIT& m_jit;

public:
  Azog(cling::IncrementalJIT& Jit): m_jit(Jit) {}

  RTDyldMemoryManager* getExeMM() const { return m_jit.m_ExeMM.get(); }

  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID,
                               StringRef SectionName) override {
    uint8_t *Addr =
      getExeMM()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID, StringRef SectionName,
                               bool IsReadOnly) override {
    uint8_t *Addr = getExeMM()->allocateDataSection(Size, Alignment, SectionID,
                                                    SectionName, IsReadOnly);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
                              uintptr_t DataSizeRW) override {
    return getExeMM()->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
  }

  bool needsToReserveAllocationSpace() override {
    return getExeMM()->needsToReserveAllocationSpace();
  }

  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                        size_t Size) override {
    return getExeMM()->registerEHFrames(Addr, LoadAddr, Size);
  }

  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                          size_t Size) override {
    return getExeMM()->deregisterEHFrames(Addr, LoadAddr, Size);
  }

  uint64_t getSymbolAddress(const std::string &Name) override {
    return m_jit.getSymbolAddressWithoutMangling(Name);
  }

  void *getPointerToNamedFunction(const std::string &Name,
                                  bool AbortOnFailure = true) override {
    return getExeMM()->getPointerToNamedFunction(Name, AbortOnFailure);
  }

  void notifyObjectLoaded(ExecutionEngine *EE,
                          const object::ObjectFile &O) override {
    return getExeMM()->notifyObjectLoaded(EE, O);
  }

  bool finalizeMemory(std::string *ErrMsg = nullptr) override {
    // Each set of objects loaded will be finalized exactly once, but since
    // symbol lookup during relocation may recursively trigger the
    // loading/relocation of other modules, and since we're forwarding all
    // finalizeMemory calls to a single underlying memory manager, we need to
    // defer forwarding the call on until all necessary objects have been
    // loaded. Otherwise, during the relocation of a leaf object, we will end
    // up finalizing memory, causing a crash further up the stack when we
    // attempt to apply relocations to finalized memory.
    // To avoid finalizing too early, look at how many objects have been
    // loaded but not yet finalized. This is a bit of a hack that relies on
    // the fact that we're lazily emitting object files: The only way you can
    // get more than one set of objects loaded but not yet finalized is if
    // they were loaded during relocation of another set.
    if (m_jit.m_UnfinalizedSections.size() == 1)
      return getExeMM()->finalizeMemory(ErrMsg);
    return false;
  };

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    std::string NameNoPrefix;
    if (MANGLE_PREFIX[0]
        && !Name.compare(0, strlen(MANGLE_PREFIX), MANGLE_PREFIX))
      NameNoPrefix = Name.substr(strlen(MANGLE_PREFIX), -1);
    else
      NameNoPrefix = std::move(Name);
    return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(NameNoPrefix);
  }

}; // class Azog

IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe,
                               std::unique_ptr<TargetMachine> TM):
  m_Parent(exe),
  m_TM(std::move(TM)),
  m_ExeMM(std::move(llvm::make_unique<ClingMemoryManager>(m_Parent))),
  m_Mang(m_TM->getDataLayout()),
  m_NotifyObjectLoaded(*this), m_NotifyFinalized(*this),
  m_ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), m_NotifyObjectLoaded,
                m_NotifyFinalized),
  m_CompileLayer(m_ObjectLayer, SimpleCompiler(*m_TM)),
  m_LazyEmitLayer(m_CompileLayer) {

  // Enable JIT symbol resolution from the binary.
  llvm::sys::DynamicLibrary::LoadLibraryPermanently(0, 0);

// #if MCJIT
//   llvm::EngineBuilder builder(std::move(m));

//   std::string errMsg;
//   builder.setErrorStr(&errMsg);
//   builder.setOptLevel(llvm::CodeGenOpt::Less);
//   builder.setEngineKind(llvm::EngineKind::JIT);
//   std::unique_ptr<llvm::RTDyldMemoryManager>
//     MemMan(new ClingMemoryManager(*this));
//   builder.setMCJITMemoryManager(std::move(MemMan));

//   // EngineBuilder uses default c'ted TargetOptions, too:
//   llvm::TargetOptions TargetOpts;
//   TargetOpts.NoFramePointerElim = 1;
//   TargetOpts.JITEmitDebugInfo = 1;

//   builder.setTargetOptions(TargetOpts);

//   m_engine.reset(builder.create());
//   assert(m_engine && "Cannot create module!");
// #endif
}

uint64_t IncrementalJIT::getSymbolAddressWithoutMangling(llvm::StringRef Name) {
  if (Name == MANGLE_PREFIX "__cxa_atexit") {
    // Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
    // coming from the JIT.
    return (uint64_t)&local_cxa_atexit;
  } else if (Name == MANGLE_PREFIX "__dso_handle") {
    // Provide IncrementalExecutor as the third argument to __cxa_atexit.
    return (uint64_t)&m_Parent;
  }
  if (uint64_t Addr = m_ExeMM->getSymbolAddress(Name))
    return Addr;
  if (uint64_t Addr = m_LazyEmitLayer.getSymbolAddress(Name, false))
    return Addr;

  return 0;
}

size_t IncrementalJIT::addModules(std::vector<llvm::Module*>&& modules) {
  // If this module doesn't have a DataLayout attached then attach the
  // default.
  for (auto&& mod: modules) {
    if (!mod->getDataLayout())
      mod->setDataLayout(m_TM->getDataLayout());
  }

  ModuleSetHandleT MSHandle
    = m_LazyEmitLayer.addModuleSet(std::move(modules),
                                   llvm::make_unique<Azog>(*this));
  m_UnloadPoints.push_back(MSHandle);
  return m_UnloadPoints.size() - 1;
}

// void* IncrementalJIT::finalizeMemory() {
//   for (auto &P : UnfinalizedSections)
//     if (P.second.count(LocalAddress))
//       ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress);
// }

void IncrementalJIT::removeModules(size_t handle) {
  m_LazyEmitLayer.removeModuleSet(m_UnloadPoints[handle]);
}

}// end namespace cling
<|endoftext|>


<commit_before>#include "Arduboy.h"
#include "audio.h"

const byte PROGMEM tune_pin_to_timer_PGM[] = { 3, 1 };
volatile byte *_tunes_timer1_pin_port;
volatile byte _tunes_timer1_pin_mask;
volatile int32_t timer1_toggle_count;
volatile byte *_tunes_timer3_pin_port;
volatile byte _tunes_timer3_pin_mask;
byte _tune_pins[AVAILABLE_TIMERS];
byte _tune_num_chans = 0;
volatile boolean tune_playing; // is the score still playing?
volatile unsigned wait_timer_frequency2;       /* its current frequency */
volatile boolean wait_timer_playing = false;   /* is it currently playing a note? */
volatile boolean tonePlaying = false;
volatile unsigned long wait_toggle_count;      /* countdown score waits */

// pointers to your musical score and your position in said score
volatile const byte *score_start = 0;
volatile const byte *score_cursor = 0;

// Table of midi note frequencies * 2
//   They are times 2 for greater accuracy, yet still fits in a word.
//   Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0<x<128
// The lowest notes might not work, depending on the Arduino clock frequency
// Ref: http://www.phy.mtu.edu/~suits/notefreqs.html
const uint8_t PROGMEM _midi_byte_note_frequencies[48] = {
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,44,46,49,52,55,58,62,65,
69,73,78,82,87,92,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,
233,247
};
const unsigned int PROGMEM _midi_word_note_frequencies[80] = {
262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,
698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,
1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,
4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902,8372,8870,9397,9956,
10548,11175,11840,12544,13290,14080,14917,15804,16744,17740,18795,19912,21096,
22351,23680,25088 };

/* AUDIO */

bool ArduboyAudio::audio_enabled = false;

void ArduboyAudio::on()
{
  // JIT audio init
  if (_tune_num_chans == 0) {
    ArduboyTunes::initChannel(PIN_SPEAKER_1);
    ArduboyTunes::initChannel(PIN_SPEAKER_2);
  }
  power_timer1_enable();
  power_timer3_enable();
  audio_enabled = true;
}

bool ArduboyAudio::enabled()
{
  return audio_enabled;
}

void ArduboyAudio::off()
{
  audio_enabled = false;
  power_timer1_disable();
  power_timer3_disable();
}

void ArduboyAudio::saveOnOff()
{
  EEPROM.write(EEPROM_AUDIO_ON_OFF, audio_enabled);
}

void ArduboyAudio::begin()
{
  tune_playing = false;
  if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
    on();
}

/* TUNES */

void ArduboyTunes::initChannel(byte pin)
{
  byte timer_num;

  // we are all out of timers
  if (_tune_num_chans == AVAILABLE_TIMERS)
    return;

  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + _tune_num_chans);
  _tune_pins[_tune_num_chans] = pin;
  _tune_num_chans++;
  pinMode(pin, OUTPUT);
  switch (timer_num) {
    case 1: // 16 bit timer
      TCCR1A = 0;
      TCCR1B = 0;
      bitWrite(TCCR1B, WGM12, 1);
      bitWrite(TCCR1B, CS10, 1);
      _tunes_timer1_pin_port = portOutputRegister(digitalPinToPort(pin));
      _tunes_timer1_pin_mask = digitalPinToBitMask(pin);
      break;
    case 3: // 16 bit timer
      TCCR3A = 0;
      TCCR3B = 0;
      bitWrite(TCCR3B, WGM32, 1);
      bitWrite(TCCR3B, CS30, 1);
      _tunes_timer3_pin_port = portOutputRegister(digitalPinToPort(pin));
      _tunes_timer3_pin_mask = digitalPinToBitMask(pin);
      playNote(0, 60);  /* start and stop channel 0 (timer 3) on middle C so wait/delay works */
      stopNote(0);
      break;
  }
}

void ArduboyTunes::playNote(byte chan, byte note)
{
  byte timer_num;
  byte prescalar_bits;
  unsigned int frequency2; /* frequency times 2 */
  unsigned long ocr;

  // we can't plan on a channel that does not exist
  if (chan >= _tune_num_chans)
    return;

  // we only have frequencies for 128 notes
  if (note > 127) {
    return;
  }

  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
  if (note < 48) {
    frequency2 = pgm_read_byte(_midi_byte_note_frequencies + note);
  } else {
    frequency2 = pgm_read_word(_midi_word_note_frequencies + note - 48);
  }

  //******  16-bit timer  *********
  // two choices for the 16 bit timers: ck/1 or ck/64
  ocr = F_CPU / frequency2 - 1;
  prescalar_bits = 0b001;
  if (ocr > 0xffff) {
    ocr = F_CPU / frequency2 / 64 - 1;
    prescalar_bits = 0b011;
  }
  // Set the OCR for the given timer, then turn on the interrupts
  switch (timer_num) {
    case 1:
      TCCR1B = (TCCR1B & 0b11111000) | prescalar_bits;
      OCR1A = ocr;
      bitWrite(TIMSK1, OCIE1A, 1);
      break;
    case 3:
      TCCR3B = (TCCR3B & 0b11111000) | prescalar_bits;
      OCR3A = ocr;
      wait_timer_frequency2 = frequency2;  // for "tune_delay" function
      wait_timer_playing = true;
      bitWrite(TIMSK3, OCIE3A, 1);
      break;
  }
}

void ArduboyTunes::stopNote(byte chan)
{
  byte timer_num;
  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
  switch (timer_num) {
    case 1:
      TIMSK1 &= ~(1 << OCIE1A);                 // disable the interrupt
      *_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask);   // keep pin low after stop
      break;
    case 3:
      wait_timer_playing = false;
      *_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask);   // keep pin low after stop
      break;
  }
}

void ArduboyTunes::playScore(const byte *score)
{
  score_start = score;
  score_cursor = score_start;
  step();  /* execute initial commands */
  tune_playing = true;  /* release the interrupt routine */
}

void ArduboyTunes::stopScore (void)
{
  for (uint8_t i = 0; i < _tune_num_chans; i++)
    stopNote(i);
  tune_playing = false;
}

bool ArduboyTunes::playing()
{
  return tune_playing;
}

/* Do score commands until a "wait" is found, or the score is stopped.
This is called initially from tune_playcore, but then is called
from the interrupt routine when waits expire.
*/
/* if CMD < 0x80, then the other 7 bits and the next byte are a 15-bit big-endian number of msec to wait */
void ArduboyTunes::step()
{
  byte command, opcode, chan;
  unsigned duration;

  while (1) {
    command = pgm_read_byte(score_cursor++);
    opcode = command & 0xf0;
    chan = command & 0x0f;
    if (opcode == TUNE_OP_STOPNOTE) { /* stop note */
      stopNote(chan);
    }
    else if (opcode == TUNE_OP_PLAYNOTE) { /* play note */
      playNote(chan, pgm_read_byte(score_cursor++));
    }
    else if (opcode == TUNE_OP_RESTART) { /* restart score */
      score_cursor = score_start;
    }
    else if (opcode == TUNE_OP_STOP) { /* stop score */
      tune_playing = false;
      break;
    }
    else if (opcode < 0x80) { /* wait count in msec. */
      duration = ((unsigned)command << 8) | (pgm_read_byte(score_cursor++));
      wait_toggle_count = ((unsigned long) wait_timer_frequency2 * duration + 500) / 1000;
      if (wait_toggle_count == 0) wait_toggle_count = 1;
      break;
    }
  }
}

void ArduboyTunes::closeChannels(void)
{
  byte timer_num;
  for (uint8_t chan=0; chan < _tune_num_chans; chan++) {
    timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
    switch (timer_num) {
      case 1:
        TIMSK1 &= ~(1 << OCIE1A);
        break;
      case 3:
        TIMSK3 &= ~(1 << OCIE3A);
        break;
    }
    digitalWrite(_tune_pins[chan], 0);
  }
  _tune_num_chans = 0;
  tune_playing = false;
}

void ArduboyTunes::soundOutput()
{
  if (wait_timer_playing) { // toggle the pin if we're sounding a note
    *_tunes_timer3_pin_port ^= _tunes_timer3_pin_mask;
  }
  if (tune_playing && wait_toggle_count && --wait_toggle_count == 0) {
    // end of a score wait, so execute more score commands
    ArduboyTunes::step();  // execute commands
  }
}

void ArduboyTunes::tone(unsigned int frequency, unsigned long duration)
{
  tonePlaying = true;
  uint8_t prescalarbits = 0b001;
  int32_t toggle_count = 0;
  uint32_t ocr = 0;

  // two choices for the 16 bit timers: ck/1 or ck/64
  ocr = F_CPU / frequency / 2 - 1;
  prescalarbits = 0b001;
  if (ocr > 0xffff) {
    ocr = F_CPU / frequency / 2 / 64 - 1;
    prescalarbits = 0b011;
  }
  TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;

  // Calculate the toggle count
  if (duration > 0) {
    toggle_count = 2 * frequency * duration / 1000;
  }
  else {
    toggle_count = -1;
  }
  // Set the OCR for the given timer,
  // set the toggle count,
  // then turn on the interrupts
  OCR1A = ocr;
  timer1_toggle_count = toggle_count;
  bitWrite(TIMSK1, OCIE1A, 1);
}

// TIMER 1
ISR(TIMER1_COMPA_vect)
{
  if (tonePlaying) {
    if (timer1_toggle_count != 0) {
      // toggle the pin
      *_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;
      if (timer1_toggle_count > 0) timer1_toggle_count--;
    }
    else {
      tonePlaying = false;
      TIMSK1 &= ~(1 << OCIE1A);                 // disable the interrupt
      *_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask);   // keep pin low after stop
    }
  }
  else {
    *_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;  // toggle the pin
  }
}

// TIMER 3
ISR(TIMER3_COMPA_vect)
{
  // Timer 3 is the one assigned first, so we keep it running always
  // and use it to time score waits, whether or not it is playing a note.
  ArduboyTunes::soundOutput();
}

<commit_msg>move tune_played default (false) to var declaration<commit_after>#include "Arduboy.h"
#include "audio.h"

const byte PROGMEM tune_pin_to_timer_PGM[] = { 3, 1 };
volatile byte *_tunes_timer1_pin_port;
volatile byte _tunes_timer1_pin_mask;
volatile int32_t timer1_toggle_count;
volatile byte *_tunes_timer3_pin_port;
volatile byte _tunes_timer3_pin_mask;
byte _tune_pins[AVAILABLE_TIMERS];
byte _tune_num_chans = 0;
volatile boolean tune_playing = false; // is the score still playing?
volatile unsigned wait_timer_frequency2;       /* its current frequency */
volatile boolean wait_timer_playing = false;   /* is it currently playing a note? */
volatile boolean tonePlaying = false;
volatile unsigned long wait_toggle_count;      /* countdown score waits */

// pointers to your musical score and your position in said score
volatile const byte *score_start = 0;
volatile const byte *score_cursor = 0;

// Table of midi note frequencies * 2
//   They are times 2 for greater accuracy, yet still fits in a word.
//   Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0<x<128
// The lowest notes might not work, depending on the Arduino clock frequency
// Ref: http://www.phy.mtu.edu/~suits/notefreqs.html
const uint8_t PROGMEM _midi_byte_note_frequencies[48] = {
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,44,46,49,52,55,58,62,65,
69,73,78,82,87,92,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,
233,247
};
const unsigned int PROGMEM _midi_word_note_frequencies[80] = {
262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,
698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,
1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,
4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902,8372,8870,9397,9956,
10548,11175,11840,12544,13290,14080,14917,15804,16744,17740,18795,19912,21096,
22351,23680,25088 };

/* AUDIO */

bool ArduboyAudio::audio_enabled = false;

void ArduboyAudio::on()
{
  // JIT audio init
  if (_tune_num_chans == 0) {
    ArduboyTunes::initChannel(PIN_SPEAKER_1);
    ArduboyTunes::initChannel(PIN_SPEAKER_2);
  }
  power_timer1_enable();
  power_timer3_enable();
  audio_enabled = true;
}

bool ArduboyAudio::enabled()
{
  return audio_enabled;
}

void ArduboyAudio::off()
{
  audio_enabled = false;
  power_timer1_disable();
  power_timer3_disable();
}

void ArduboyAudio::saveOnOff()
{
  EEPROM.write(EEPROM_AUDIO_ON_OFF, audio_enabled);
}

void ArduboyAudio::begin()
{
  if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
    on();
}

/* TUNES */

void ArduboyTunes::initChannel(byte pin)
{
  byte timer_num;

  // we are all out of timers
  if (_tune_num_chans == AVAILABLE_TIMERS)
    return;

  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + _tune_num_chans);
  _tune_pins[_tune_num_chans] = pin;
  _tune_num_chans++;
  pinMode(pin, OUTPUT);
  switch (timer_num) {
    case 1: // 16 bit timer
      TCCR1A = 0;
      TCCR1B = 0;
      bitWrite(TCCR1B, WGM12, 1);
      bitWrite(TCCR1B, CS10, 1);
      _tunes_timer1_pin_port = portOutputRegister(digitalPinToPort(pin));
      _tunes_timer1_pin_mask = digitalPinToBitMask(pin);
      break;
    case 3: // 16 bit timer
      TCCR3A = 0;
      TCCR3B = 0;
      bitWrite(TCCR3B, WGM32, 1);
      bitWrite(TCCR3B, CS30, 1);
      _tunes_timer3_pin_port = portOutputRegister(digitalPinToPort(pin));
      _tunes_timer3_pin_mask = digitalPinToBitMask(pin);
      playNote(0, 60);  /* start and stop channel 0 (timer 3) on middle C so wait/delay works */
      stopNote(0);
      break;
  }
}

void ArduboyTunes::playNote(byte chan, byte note)
{
  byte timer_num;
  byte prescalar_bits;
  unsigned int frequency2; /* frequency times 2 */
  unsigned long ocr;

  // we can't plan on a channel that does not exist
  if (chan >= _tune_num_chans)
    return;

  // we only have frequencies for 128 notes
  if (note > 127) {
    return;
  }

  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
  if (note < 48) {
    frequency2 = pgm_read_byte(_midi_byte_note_frequencies + note);
  } else {
    frequency2 = pgm_read_word(_midi_word_note_frequencies + note - 48);
  }

  //******  16-bit timer  *********
  // two choices for the 16 bit timers: ck/1 or ck/64
  ocr = F_CPU / frequency2 - 1;
  prescalar_bits = 0b001;
  if (ocr > 0xffff) {
    ocr = F_CPU / frequency2 / 64 - 1;
    prescalar_bits = 0b011;
  }
  // Set the OCR for the given timer, then turn on the interrupts
  switch (timer_num) {
    case 1:
      TCCR1B = (TCCR1B & 0b11111000) | prescalar_bits;
      OCR1A = ocr;
      bitWrite(TIMSK1, OCIE1A, 1);
      break;
    case 3:
      TCCR3B = (TCCR3B & 0b11111000) | prescalar_bits;
      OCR3A = ocr;
      wait_timer_frequency2 = frequency2;  // for "tune_delay" function
      wait_timer_playing = true;
      bitWrite(TIMSK3, OCIE3A, 1);
      break;
  }
}

void ArduboyTunes::stopNote(byte chan)
{
  byte timer_num;
  timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
  switch (timer_num) {
    case 1:
      TIMSK1 &= ~(1 << OCIE1A);                 // disable the interrupt
      *_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask);   // keep pin low after stop
      break;
    case 3:
      wait_timer_playing = false;
      *_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask);   // keep pin low after stop
      break;
  }
}

void ArduboyTunes::playScore(const byte *score)
{
  score_start = score;
  score_cursor = score_start;
  step();  /* execute initial commands */
  tune_playing = true;  /* release the interrupt routine */
}

void ArduboyTunes::stopScore (void)
{
  for (uint8_t i = 0; i < _tune_num_chans; i++)
    stopNote(i);
  tune_playing = false;
}

bool ArduboyTunes::playing()
{
  return tune_playing;
}

/* Do score commands until a "wait" is found, or the score is stopped.
This is called initially from tune_playcore, but then is called
from the interrupt routine when waits expire.
*/
/* if CMD < 0x80, then the other 7 bits and the next byte are a 15-bit big-endian number of msec to wait */
void ArduboyTunes::step()
{
  byte command, opcode, chan;
  unsigned duration;

  while (1) {
    command = pgm_read_byte(score_cursor++);
    opcode = command & 0xf0;
    chan = command & 0x0f;
    if (opcode == TUNE_OP_STOPNOTE) { /* stop note */
      stopNote(chan);
    }
    else if (opcode == TUNE_OP_PLAYNOTE) { /* play note */
      playNote(chan, pgm_read_byte(score_cursor++));
    }
    else if (opcode == TUNE_OP_RESTART) { /* restart score */
      score_cursor = score_start;
    }
    else if (opcode == TUNE_OP_STOP) { /* stop score */
      tune_playing = false;
      break;
    }
    else if (opcode < 0x80) { /* wait count in msec. */
      duration = ((unsigned)command << 8) | (pgm_read_byte(score_cursor++));
      wait_toggle_count = ((unsigned long) wait_timer_frequency2 * duration + 500) / 1000;
      if (wait_toggle_count == 0) wait_toggle_count = 1;
      break;
    }
  }
}

void ArduboyTunes::closeChannels(void)
{
  byte timer_num;
  for (uint8_t chan=0; chan < _tune_num_chans; chan++) {
    timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
    switch (timer_num) {
      case 1:
        TIMSK1 &= ~(1 << OCIE1A);
        break;
      case 3:
        TIMSK3 &= ~(1 << OCIE3A);
        break;
    }
    digitalWrite(_tune_pins[chan], 0);
  }
  _tune_num_chans = 0;
  tune_playing = false;
}

void ArduboyTunes::soundOutput()
{
  if (wait_timer_playing) { // toggle the pin if we're sounding a note
    *_tunes_timer3_pin_port ^= _tunes_timer3_pin_mask;
  }
  if (tune_playing && wait_toggle_count && --wait_toggle_count == 0) {
    // end of a score wait, so execute more score commands
    ArduboyTunes::step();  // execute commands
  }
}

void ArduboyTunes::tone(unsigned int frequency, unsigned long duration)
{
  tonePlaying = true;
  uint8_t prescalarbits = 0b001;
  int32_t toggle_count = 0;
  uint32_t ocr = 0;

  // two choices for the 16 bit timers: ck/1 or ck/64
  ocr = F_CPU / frequency / 2 - 1;
  prescalarbits = 0b001;
  if (ocr > 0xffff) {
    ocr = F_CPU / frequency / 2 / 64 - 1;
    prescalarbits = 0b011;
  }
  TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;

  // Calculate the toggle count
  if (duration > 0) {
    toggle_count = 2 * frequency * duration / 1000;
  }
  else {
    toggle_count = -1;
  }
  // Set the OCR for the given timer,
  // set the toggle count,
  // then turn on the interrupts
  OCR1A = ocr;
  timer1_toggle_count = toggle_count;
  bitWrite(TIMSK1, OCIE1A, 1);
}

// TIMER 1
ISR(TIMER1_COMPA_vect)
{
  if (tonePlaying) {
    if (timer1_toggle_count != 0) {
      // toggle the pin
      *_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;
      if (timer1_toggle_count > 0) timer1_toggle_count--;
    }
    else {
      tonePlaying = false;
      TIMSK1 &= ~(1 << OCIE1A);                 // disable the interrupt
      *_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask);   // keep pin low after stop
    }
  }
  else {
    *_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;  // toggle the pin
  }
}

// TIMER 3
ISR(TIMER3_COMPA_vect)
{
  // Timer 3 is the one assigned first, so we keep it running always
  // and use it to time score waits, whether or not it is playing a note.
  ArduboyTunes::soundOutput();
}

<|endoftext|>


<commit_before>#include <TestSupport.h>
#include <jsoncpp/json.h>
#include <Core/SpawningKit/SmartSpawner.h>
#include <Logging.h>
#include <FileDescriptor.h>
#include <Utils/IOUtils.h>
#include <unistd.h>
#include <climits>
#include <signal.h>
#include <fcntl.h>

using namespace std;
using namespace Passenger;
using namespace Passenger::SpawningKit;

namespace tut {
	struct Core_SpawningKit_SmartSpawnerTest {
		ConfigPtr config;
		OutputHandler gatherOutput;
		string gatheredOutput;
		boost::mutex gatheredOutputSyncher;
		SpawningKit::Result result;

		Core_SpawningKit_SmartSpawnerTest() {
			config = boost::make_shared<Config>();
			config->resourceLocator = resourceLocator;
			config->finalize();

			gatherOutput = boost::bind(&Core_SpawningKit_SmartSpawnerTest::_gatherOutput, this, _1, _2);
			setLogLevel(LVL_WARN);
			setPrintAppOutputAsDebuggingMessages(true);
		}

		~Core_SpawningKit_SmartSpawnerTest() {
			setLogLevel(DEFAULT_LOG_LEVEL);
			setPrintAppOutputAsDebuggingMessages(false);
			unlink("stub/wsgi/passenger_wsgi.pyc");
		}

		boost::shared_ptr<SmartSpawner> createSpawner(const Options &options, bool exitImmediately = false) {
			char buf[PATH_MAX + 1];
			getcwd(buf, PATH_MAX);

			vector<string> command;
			command.push_back("ruby");
			command.push_back(string(buf) + "/support/placebo-preloader.rb");
			if (exitImmediately) {
				command.push_back("exit-immediately");
			}

			return boost::make_shared<SmartSpawner>(command,
				options, config);
		}

		Options createOptions() {
			Options options;
			options.spawnMethod = "smart";
			options.loadShellEnvvars = false;
			return options;
		}

		void _gatherOutput(const char *data, unsigned int size) {
			boost::lock_guard<boost::mutex> l(gatheredOutputSyncher);
			gatheredOutput.append(data, size);
		}
	};

	DEFINE_TEST_GROUP_WITH_LIMIT(Core_SpawningKit_SmartSpawnerTest, 90);

	#include "SpawnerTestCases.cpp"

	TEST_METHOD(80) {
		set_test_name("If the preloader has crashed then SmartSpawner will "
			"restart it and try again");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		boost::shared_ptr<SmartSpawner> spawner = createSpawner(options);
		setLogLevel(LVL_CRIT);
		spawner->spawn(options);

		kill(spawner->getPreloaderPid(), SIGTERM);
		// Give it some time to exit.
		usleep(300000);

		// No exception at next spawn.
		spawner->spawn(options);
	}

	TEST_METHOD(81) {
		set_test_name("If the preloader still crashes after the restart then "
			"SmartSpawner will throw an exception");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		setLogLevel(LVL_CRIT);
		boost::shared_ptr<SmartSpawner> spawner = createSpawner(options, true);
		try {
			spawner->spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &) {
			// Pass.
		}
	}

	TEST_METHOD(82) {
		set_test_name("If the preloader didn't start within the timeout "
			"then it's killed and an exception is thrown, with "
			"whatever stderr output as error page");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		options.startTimeout = 100;

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2; sleep 60");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure_equals(e.getErrorKind(),
				SpawnException::PRELOADER_STARTUP_TIMEOUT);
			if (e.getErrorPage().find("hello world\n") == string::npos) {
				// This might be caused by the machine being too slow.
				// Try again with a higher timeout.
#if defined(BOOST_OS_MACOS)
				options.startTimeout = 2000;
#else
				options.startTimeout = 1000;
#endif
				SmartSpawner spawner2(preloaderCommand, options, config);
				try {
					spawner2.spawn(options);
					fail("SpawnException expected");
				} catch (const SpawnException &e2) {
					ensure_equals(e2.getErrorKind(),
						SpawnException::PRELOADER_STARTUP_TIMEOUT);
					if (e2.getErrorPage().find("hello world\n") == string::npos) {
						fail(("Unexpected error page:\n" + e2.getErrorPage()).c_str());
					}
				}
			}
		}
	}

	TEST_METHOD(83) {
		set_test_name("If the preloader crashed during startup without returning "
			"a proper error response, then its stderr output is used "
			"as error response instead");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure_equals(e.getErrorKind(),
				SpawnException::PRELOADER_STARTUP_ERROR);
			ensure(e.getErrorPage().find("hello world\n") != string::npos);
		}
	}

	TEST_METHOD(84) {
		set_test_name("If the preloader encountered an error, then the resulting SpawnException "
			"takes note of the process's environment variables");
		string envvars = modp::b64_encode("PASSENGER_FOO\0foo\0",
			sizeof("PASSENGER_FOO\0foo\0") - 1);
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		options.environmentVariables = envvars;

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure(containsSubstring(e["envvars"], "PASSENGER_FOO=foo\n"));
		}
	}

	TEST_METHOD(85) {
		set_test_name("The spawned process can still write to its stderr "
			"after the SmartSpawner has been destroyed");
		DeleteFileEventually d("tmp.output");
		config->outputHandler = gatherOutput;
		Options options = createOptions();
		options.appRoot = "stub/rack";
		options.appType = "rack";

		{
			vector<string> preloaderCommand;
			preloaderCommand.push_back("ruby");
			preloaderCommand.push_back(resourceLocator->getHelperScriptsDir() +
				"/rack-preloader.rb");
			SmartSpawner spawner(preloaderCommand, options, config);
			result = spawner.spawn(options);
		}

		const char header[] =
			"REQUEST_METHOD\0GET\0"
			"PATH_INFO\0/print_stderr\0";

		FileDescriptor fd(connectToServer(result["sockets"][0]["address"].asCString(),
			__FILE__, __LINE__), NULL, 0);
		writeScalarMessage(fd, header, sizeof(header) - 1);
		shutdown(fd, SHUT_WR);
		readAll(fd);
		EVENTUALLY(2,
			boost::lock_guard<boost::mutex> l(gatheredOutputSyncher);
			result = gatheredOutput.find("hello world!\n") != string::npos;
		);
	}
}
<commit_msg>increase timeout for osx CI<commit_after>#include <TestSupport.h>
#include <jsoncpp/json.h>
#include <Core/SpawningKit/SmartSpawner.h>
#include <Logging.h>
#include <FileDescriptor.h>
#include <Utils/IOUtils.h>
#include <unistd.h>
#include <climits>
#include <signal.h>
#include <fcntl.h>

using namespace std;
using namespace Passenger;
using namespace Passenger::SpawningKit;

namespace tut {
	struct Core_SpawningKit_SmartSpawnerTest {
		ConfigPtr config;
		OutputHandler gatherOutput;
		string gatheredOutput;
		boost::mutex gatheredOutputSyncher;
		SpawningKit::Result result;

		Core_SpawningKit_SmartSpawnerTest() {
			config = boost::make_shared<Config>();
			config->resourceLocator = resourceLocator;
			config->finalize();

			gatherOutput = boost::bind(&Core_SpawningKit_SmartSpawnerTest::_gatherOutput, this, _1, _2);
			setLogLevel(LVL_WARN);
			setPrintAppOutputAsDebuggingMessages(true);
		}

		~Core_SpawningKit_SmartSpawnerTest() {
			setLogLevel(DEFAULT_LOG_LEVEL);
			setPrintAppOutputAsDebuggingMessages(false);
			unlink("stub/wsgi/passenger_wsgi.pyc");
		}

		boost::shared_ptr<SmartSpawner> createSpawner(const Options &options, bool exitImmediately = false) {
			char buf[PATH_MAX + 1];
			getcwd(buf, PATH_MAX);

			vector<string> command;
			command.push_back("ruby");
			command.push_back(string(buf) + "/support/placebo-preloader.rb");
			if (exitImmediately) {
				command.push_back("exit-immediately");
			}

			return boost::make_shared<SmartSpawner>(command,
				options, config);
		}

		Options createOptions() {
			Options options;
			options.spawnMethod = "smart";
			options.loadShellEnvvars = false;
			return options;
		}

		void _gatherOutput(const char *data, unsigned int size) {
			boost::lock_guard<boost::mutex> l(gatheredOutputSyncher);
			gatheredOutput.append(data, size);
		}
	};

	DEFINE_TEST_GROUP_WITH_LIMIT(Core_SpawningKit_SmartSpawnerTest, 90);

	#include "SpawnerTestCases.cpp"

	TEST_METHOD(80) {
		set_test_name("If the preloader has crashed then SmartSpawner will "
			"restart it and try again");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		boost::shared_ptr<SmartSpawner> spawner = createSpawner(options);
		setLogLevel(LVL_CRIT);
		spawner->spawn(options);

		kill(spawner->getPreloaderPid(), SIGTERM);
		// Give it some time to exit.
		usleep(300000);

		// No exception at next spawn.
		spawner->spawn(options);
	}

	TEST_METHOD(81) {
		set_test_name("If the preloader still crashes after the restart then "
			"SmartSpawner will throw an exception");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		setLogLevel(LVL_CRIT);
		boost::shared_ptr<SmartSpawner> spawner = createSpawner(options, true);
		try {
			spawner->spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &) {
			// Pass.
		}
	}

	TEST_METHOD(82) {
		set_test_name("If the preloader didn't start within the timeout "
			"then it's killed and an exception is thrown, with "
			"whatever stderr output as error page");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		options.startTimeout = 100;

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2; sleep 60");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure_equals(e.getErrorKind(),
				SpawnException::PRELOADER_STARTUP_TIMEOUT);
			if (e.getErrorPage().find("hello world\n") == string::npos) {
				// This might be caused by the machine being too slow.
				// Try again with a higher timeout.
#if defined(BOOST_OS_MACOS)
				options.startTimeout = 3000;
#else
				options.startTimeout = 1000;
#endif
				SmartSpawner spawner2(preloaderCommand, options, config);
				try {
					spawner2.spawn(options);
					fail("SpawnException expected");
				} catch (const SpawnException &e2) {
					ensure_equals(e2.getErrorKind(),
						SpawnException::PRELOADER_STARTUP_TIMEOUT);
					if (e2.getErrorPage().find("hello world\n") == string::npos) {
						fail(("Unexpected error page:\n" + e2.getErrorPage()).c_str());
					}
				}
			}
		}
	}

	TEST_METHOD(83) {
		set_test_name("If the preloader crashed during startup without returning "
			"a proper error response, then its stderr output is used "
			"as error response instead");
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure_equals(e.getErrorKind(),
				SpawnException::PRELOADER_STARTUP_ERROR);
			ensure(e.getErrorPage().find("hello world\n") != string::npos);
		}
	}

	TEST_METHOD(84) {
		set_test_name("If the preloader encountered an error, then the resulting SpawnException "
			"takes note of the process's environment variables");
		string envvars = modp::b64_encode("PASSENGER_FOO\0foo\0",
			sizeof("PASSENGER_FOO\0foo\0") - 1);
		Options options = createOptions();
		options.appRoot      = "stub/rack";
		options.startCommand = "ruby\t" "start.rb";
		options.startupFile  = "start.rb";
		options.environmentVariables = envvars;

		vector<string> preloaderCommand;
		preloaderCommand.push_back("bash");
		preloaderCommand.push_back("-c");
		preloaderCommand.push_back("echo hello world >&2");
		SmartSpawner spawner(preloaderCommand, options, config);
		setLogLevel(LVL_CRIT);

		try {
			spawner.spawn(options);
			fail("SpawnException expected");
		} catch (const SpawnException &e) {
			ensure(containsSubstring(e["envvars"], "PASSENGER_FOO=foo\n"));
		}
	}

	TEST_METHOD(85) {
		set_test_name("The spawned process can still write to its stderr "
			"after the SmartSpawner has been destroyed");
		DeleteFileEventually d("tmp.output");
		config->outputHandler = gatherOutput;
		Options options = createOptions();
		options.appRoot = "stub/rack";
		options.appType = "rack";

		{
			vector<string> preloaderCommand;
			preloaderCommand.push_back("ruby");
			preloaderCommand.push_back(resourceLocator->getHelperScriptsDir() +
				"/rack-preloader.rb");
			SmartSpawner spawner(preloaderCommand, options, config);
			result = spawner.spawn(options);
		}

		const char header[] =
			"REQUEST_METHOD\0GET\0"
			"PATH_INFO\0/print_stderr\0";

		FileDescriptor fd(connectToServer(result["sockets"][0]["address"].asCString(),
			__FILE__, __LINE__), NULL, 0);
		writeScalarMessage(fd, header, sizeof(header) - 1);
		shutdown(fd, SHUT_WR);
		readAll(fd);
		EVENTUALLY(2,
			boost::lock_guard<boost::mutex> l(gatheredOutputSyncher);
			result = gatheredOutput.find("hello world!\n") != string::npos;
		);
	}
}
<|endoftext|>