<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  libtest
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <config.h>
#include <libtest/common.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctime>
#include <fnmatch.h>
#include <iostream>

#include <signal.h>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

using namespace libtest;

static void stats_print(Stats *stats)
{
  if (stats->collection_failed == 0 and stats->collection_success == 0)
  {
    return;
  }

  Out << "\tTotal Collections\t\t\t\t" << stats->collection_total;
  Out << "\tFailed Collections\t\t\t\t" << stats->collection_failed;
  Out << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped;
  Out << "\tSucceeded Collections\t\t\t\t" << stats->collection_success;
  Outn();
  Out << "Total\t\t\t\t" << stats->total;
  Out << "\tFailed\t\t\t" << stats->failed;
  Out << "\tSkipped\t\t\t" << stats->skipped;
  Out << "\tSucceeded\t\t" << stats->success;
}

static long int timedif(struct timeval a, struct timeval b)
{
  long us, s;

  us = (long)(a.tv_usec - b.tv_usec);
  us /= 1000;
  s = (long)(a.tv_sec - b.tv_sec);
  s *= 1000;
  return s + us;
}

#include <getopt.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  bool opt_massive= false;
  unsigned long int opt_repeat= 1; // Run all tests once
  bool opt_quiet= false;
  std::string collection_to_run;

  // Options parsing
  {
    enum long_option_t {
      OPT_LIBYATL_VERSION,
      OPT_LIBYATL_MATCH_COLLECTION,
      OPT_LIBYATL_MASSIVE,
      OPT_LIBYATL_QUIET,
      OPT_LIBYATL_REPEAT
    };

    static struct option long_options[]=
    {
      { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
      { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
      { "repeat", no_argument, NULL, OPT_LIBYATL_REPEAT },
      { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
      { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
      { 0, 0, 0, 0 }
    };

    int option_index= 0;
    while (1)
    {
      int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
      if (option_rv == -1)
      {
        break;
      }

      switch (option_rv)
      {
      case OPT_LIBYATL_VERSION:
        break;

      case OPT_LIBYATL_QUIET:
        opt_quiet= true;
        break;

      case OPT_LIBYATL_REPEAT:
        opt_repeat= strtoul(optarg, (char **) NULL, 10);
        break;

      case OPT_LIBYATL_MATCH_COLLECTION:
        collection_to_run= optarg;
        break;

      case OPT_LIBYATL_MASSIVE:
        opt_massive= true;
        break;

      case '?':
        /* getopt_long already printed an error message. */
        Error << "unknown option to getopt_long()";
        exit(EXIT_FAILURE);

      default:
        break;
      }
    }
  }

  srandom((unsigned int)time(NULL));

  if (bool(getenv("YATL_REPEAT")) and (strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10) > 1))
  {
    opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
  }

  if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
  {
    opt_quiet= true;
  }
  else if (getenv("JENKINS_URL"))
  {
    if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
    { }
    else
    {
      opt_quiet= true;
    }
  }

  if (opt_quiet)
  {
    close(STDOUT_FILENO);
  }

  char buffer[1024];
  if (getenv("LIBTEST_TMP"))
  {
    snprintf(buffer, sizeof(buffer), "%s", getenv("LIBTEST_TMP"));
  }
  else
  {
    snprintf(buffer, sizeof(buffer), "%s", LIBTEST_TEMP);
  }

  if (chdir(buffer) == -1)
  {
    char getcwd_buffer[1024];
    char *dir= getcwd(getcwd_buffer, sizeof(getcwd_buffer));

    Error << "Unable to chdir() from " << dir << " to " << buffer << " errno:" << strerror(errno);
    return EXIT_FAILURE;
  }

  if (libtest::libtool() == NULL)
  {
    Error << "Failed to locate libtool";
    return EXIT_FAILURE;
  }

  int exit_code;

  try {
    do {
      exit_code= EXIT_SUCCESS;
      Framework world;

      fatal_assert(sigignore(SIGPIPE) == 0);

      libtest::SignalThread signal;
      if (signal.setup() == false)
      {
        Error << "Failed to setup signals";
        return EXIT_FAILURE;
      }

      Stats stats;

      get_world(&world);

      test_return_t error;
      void *creators_ptr= world.create(error);

      switch (error)
      {
      case TEST_SUCCESS:
        break;

      case TEST_SKIPPED:
        Out << "SKIP " << argv[0];
        return EXIT_SUCCESS;

      case TEST_FAILURE:
        return EXIT_FAILURE;
      }

      if (getenv("YATL_COLLECTION_TO_RUN"))
      {
        if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
        {
          collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
        }
      }

      if (collection_to_run.empty() == false)
      {
        Out << "Only testing " <<  collection_to_run;
      }

      char *wildcard= NULL;
      if (argc == 3)
      {
        wildcard= argv[2];
      }

      for (collection_st *next= world.collections; next and next->name and (not signal.is_shutdown()); next++)
      {
        bool failed= false;
        bool skipped= false;

        if (collection_to_run.empty() == false and fnmatch(collection_to_run.c_str(), next->name, 0))
        {
          continue;
        }

        stats.collection_total++;

        test_return_t collection_rc= world.startup(creators_ptr);

        if (collection_rc == TEST_SUCCESS and next->pre)
        {
          collection_rc= world.runner()->pre(next->pre, creators_ptr);
        }

        switch (collection_rc)
        {
        case TEST_SUCCESS:
          break;

        case TEST_FAILURE:
          Out << next->name << " [ failed ]";
          failed= true;
          signal.set_shutdown(SHUTDOWN_GRACEFUL);
          goto cleanup;

        case TEST_SKIPPED:
          Out << next->name << " [ skipping ]";
          skipped= true;
          goto cleanup;

        default:
          fatal_message("invalid return code");
        }

        Out << "Collection: " << next->name;

        for (test_st *run= next->tests; run->name; run++)
        {
          struct timeval start_time, end_time;
          long int load_time= 0;

          if (wildcard && fnmatch(wildcard, run->name, 0))
          {
            continue;
          }

          test_return_t return_code;
          try {
            if (test_success(return_code= world.item.startup(creators_ptr)))
            {
              if (test_success(return_code= world.item.flush(creators_ptr, run)))
              {
                // @note pre will fail is SKIPPED is returned
                if (test_success(return_code= world.item.pre(creators_ptr)))
                {
                  { // Runner Code
                    gettimeofday(&start_time, NULL);
                    assert(world.runner());
                    assert(run->test_fn);
                    try
                    {
                      return_code= world.runner()->run(run->test_fn, creators_ptr);
                    }
                    // Special case where check for the testing of the exception
                    // system.
                    catch (libtest::fatal &e)
                    {
                      if (fatal::is_disabled())
                      {
                        fatal::increment_disabled_counter();
                        return_code= TEST_SUCCESS;
                      }
                      else
                      {
                        throw;
                      }
                    }

                    gettimeofday(&end_time, NULL);
                    load_time= timedif(end_time, start_time);
                  }
                }

                // @todo do something if post fails
                (void)world.item.post(creators_ptr);
              }
              else if (return_code == TEST_SKIPPED)
              { }
              else if (return_code == TEST_FAILURE)
              {
                Error << " item.flush(failure)";
                signal.set_shutdown(SHUTDOWN_GRACEFUL);
              }
            }
            else if (return_code == TEST_SKIPPED)
            { }
            else if (return_code == TEST_FAILURE)
            {
              Error << " item.startup(failure)";
              signal.set_shutdown(SHUTDOWN_GRACEFUL);
            }
          }

          catch (libtest::fatal &e)
          {
            Error << "Fatal exception was thrown: " << e.what();
            return_code= TEST_FAILURE;
          }
          catch (std::exception &e)
          {
            Error << "Exception was thrown: " << e.what();
            return_code= TEST_FAILURE;
          }
          catch (...)
          {
            Error << "Unknown exception occurred";
            return_code= TEST_FAILURE;
          }

          stats.total++;

          switch (return_code)
          {
          case TEST_SUCCESS:
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
            stats.success++;
            break;

          case TEST_FAILURE:
            stats.failed++;
            failed= true;
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
            break;

          case TEST_SKIPPED:
            stats.skipped++;
            skipped= true;
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
            break;

          default:
            fatal_message("invalid return code");
          }

          if (test_failed(world.on_error(return_code, creators_ptr)))
          {
            Error << "Failed while running on_error()";
            signal.set_shutdown(SHUTDOWN_GRACEFUL);
            break;
          }
        }

        (void) world.runner()->post(next->post, creators_ptr);

cleanup:
        if (failed == false and skipped == false)
        {
          stats.collection_success++;
        }

        if (failed)
        {
          stats.collection_failed++;
        }

        if (skipped)
        {
          stats.collection_skipped++;
        }

        world.shutdown(creators_ptr);
        Outn();
      }

      if (not signal.is_shutdown())
      {
        signal.set_shutdown(SHUTDOWN_GRACEFUL);
      }

      shutdown_t status= signal.get_shutdown();
      if (status == SHUTDOWN_FORCED)
      {
        Out << "Tests were aborted.";
        exit_code= EXIT_FAILURE;
      }
      else if (stats.collection_failed)
      {
        Out << "Some test failed.";
        exit_code= EXIT_FAILURE;
      }
      else if (stats.collection_skipped and stats.collection_failed and stats.collection_success)
      {
        Out << "Some tests were skipped.";
      }
      else if (stats.collection_success and stats.collection_failed == 0)
      {
        Out << "All tests completed successfully.";
      }

      stats_print(&stats);

      Outn(); // Generate a blank to break up the messages if make check/test has been run
    } while (exit_code == EXIT_SUCCESS and --opt_repeat);
  }
  catch (libtest::fatal& e)
  {
    std::cerr << e.what() << std::endl;
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  catch (...)
  {
    std::cerr << "Unknown exception halted execution." << std::endl;
  }

  return exit_code;
}
<commit_msg>Give the option to just bail on all tests.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  libtest
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <config.h>
#include <libtest/common.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctime>
#include <fnmatch.h>
#include <iostream>

#include <signal.h>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

using namespace libtest;

static void stats_print(Stats *stats)
{
  if (stats->collection_failed == 0 and stats->collection_success == 0)
  {
    return;
  }

  Out << "\tTotal Collections\t\t\t\t" << stats->collection_total;
  Out << "\tFailed Collections\t\t\t\t" << stats->collection_failed;
  Out << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped;
  Out << "\tSucceeded Collections\t\t\t\t" << stats->collection_success;
  Outn();
  Out << "Total\t\t\t\t" << stats->total;
  Out << "\tFailed\t\t\t" << stats->failed;
  Out << "\tSkipped\t\t\t" << stats->skipped;
  Out << "\tSucceeded\t\t" << stats->success;
}

static long int timedif(struct timeval a, struct timeval b)
{
  long us, s;

  us = (long)(a.tv_usec - b.tv_usec);
  us /= 1000;
  s = (long)(a.tv_sec - b.tv_sec);
  s *= 1000;
  return s + us;
}

#include <getopt.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  bool opt_massive= false;
  unsigned long int opt_repeat= 1; // Run all tests once
  bool opt_quiet= false;
  std::string collection_to_run;

  // Options parsing
  {
    enum long_option_t {
      OPT_LIBYATL_VERSION,
      OPT_LIBYATL_MATCH_COLLECTION,
      OPT_LIBYATL_MASSIVE,
      OPT_LIBYATL_QUIET,
      OPT_LIBYATL_REPEAT
    };

    static struct option long_options[]=
    {
      { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
      { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
      { "repeat", no_argument, NULL, OPT_LIBYATL_REPEAT },
      { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
      { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
      { 0, 0, 0, 0 }
    };

    int option_index= 0;
    while (1)
    {
      int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
      if (option_rv == -1)
      {
        break;
      }

      switch (option_rv)
      {
      case OPT_LIBYATL_VERSION:
        break;

      case OPT_LIBYATL_QUIET:
        opt_quiet= true;
        break;

      case OPT_LIBYATL_REPEAT:
        opt_repeat= strtoul(optarg, (char **) NULL, 10);
        break;

      case OPT_LIBYATL_MATCH_COLLECTION:
        collection_to_run= optarg;
        break;

      case OPT_LIBYATL_MASSIVE:
        opt_massive= true;
        break;

      case '?':
        /* getopt_long already printed an error message. */
        Error << "unknown option to getopt_long()";
        exit(EXIT_FAILURE);

      default:
        break;
      }
    }
  }

  srandom((unsigned int)time(NULL));

  if (bool(getenv("YATL_REPEAT")) and (strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10) > 1))
  {
    opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
  }

  if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
  {
    opt_quiet= true;
  }
  else if (getenv("JENKINS_URL"))
  {
    if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
    { }
    else
    {
      opt_quiet= true;
    }
  }

  if (opt_quiet)
  {
    close(STDOUT_FILENO);
  }

  char buffer[1024];
  if (getenv("LIBTEST_TMP"))
  {
    snprintf(buffer, sizeof(buffer), "%s", getenv("LIBTEST_TMP"));
  }
  else
  {
    snprintf(buffer, sizeof(buffer), "%s", LIBTEST_TEMP);
  }

  if (chdir(buffer) == -1)
  {
    char getcwd_buffer[1024];
    char *dir= getcwd(getcwd_buffer, sizeof(getcwd_buffer));

    Error << "Unable to chdir() from " << dir << " to " << buffer << " errno:" << strerror(errno);
    return EXIT_FAILURE;
  }

  if (libtest::libtool() == NULL)
  {
    Error << "Failed to locate libtool";
    return EXIT_FAILURE;
  }

  int exit_code;

  try {
    do {
      exit_code= EXIT_SUCCESS;
      Framework world;

      fatal_assert(sigignore(SIGPIPE) == 0);

      libtest::SignalThread signal;
      if (signal.setup() == false)
      {
        Error << "Failed to setup signals";
        return EXIT_FAILURE;
      }

      Stats stats;

      get_world(&world);

      test_return_t error;
      void *creators_ptr= world.create(error);

      switch (error)
      {
      case TEST_SUCCESS:
        break;

      case TEST_SKIPPED:
        Out << "SKIP " << argv[0];
        return EXIT_SUCCESS;

      case TEST_FAILURE:
        return EXIT_FAILURE;
      }

      if (getenv("YATL_COLLECTION_TO_RUN"))
      {
        if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
        {
          collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
        }
      }

      if (collection_to_run.compare("none") == 0)
      {
        return EXIT_SUCCESS;
      }

      if (collection_to_run.empty() == false)
      {
        Out << "Only testing " <<  collection_to_run;
      }

      char *wildcard= NULL;
      if (argc == 3)
      {
        wildcard= argv[2];
      }

      for (collection_st *next= world.collections; next and next->name and (not signal.is_shutdown()); next++)
      {
        bool failed= false;
        bool skipped= false;

        if (collection_to_run.empty() == false and fnmatch(collection_to_run.c_str(), next->name, 0))
        {
          continue;
        }

        stats.collection_total++;

        test_return_t collection_rc= world.startup(creators_ptr);

        if (collection_rc == TEST_SUCCESS and next->pre)
        {
          collection_rc= world.runner()->pre(next->pre, creators_ptr);
        }

        switch (collection_rc)
        {
        case TEST_SUCCESS:
          break;

        case TEST_FAILURE:
          Out << next->name << " [ failed ]";
          failed= true;
          signal.set_shutdown(SHUTDOWN_GRACEFUL);
          goto cleanup;

        case TEST_SKIPPED:
          Out << next->name << " [ skipping ]";
          skipped= true;
          goto cleanup;

        default:
          fatal_message("invalid return code");
        }

        Out << "Collection: " << next->name;

        for (test_st *run= next->tests; run->name; run++)
        {
          struct timeval start_time, end_time;
          long int load_time= 0;

          if (wildcard && fnmatch(wildcard, run->name, 0))
          {
            continue;
          }

          test_return_t return_code;
          try {
            if (test_success(return_code= world.item.startup(creators_ptr)))
            {
              if (test_success(return_code= world.item.flush(creators_ptr, run)))
              {
                // @note pre will fail is SKIPPED is returned
                if (test_success(return_code= world.item.pre(creators_ptr)))
                {
                  { // Runner Code
                    gettimeofday(&start_time, NULL);
                    assert(world.runner());
                    assert(run->test_fn);
                    try
                    {
                      return_code= world.runner()->run(run->test_fn, creators_ptr);
                    }
                    // Special case where check for the testing of the exception
                    // system.
                    catch (libtest::fatal &e)
                    {
                      if (fatal::is_disabled())
                      {
                        fatal::increment_disabled_counter();
                        return_code= TEST_SUCCESS;
                      }
                      else
                      {
                        throw;
                      }
                    }

                    gettimeofday(&end_time, NULL);
                    load_time= timedif(end_time, start_time);
                  }
                }

                // @todo do something if post fails
                (void)world.item.post(creators_ptr);
              }
              else if (return_code == TEST_SKIPPED)
              { }
              else if (return_code == TEST_FAILURE)
              {
                Error << " item.flush(failure)";
                signal.set_shutdown(SHUTDOWN_GRACEFUL);
              }
            }
            else if (return_code == TEST_SKIPPED)
            { }
            else if (return_code == TEST_FAILURE)
            {
              Error << " item.startup(failure)";
              signal.set_shutdown(SHUTDOWN_GRACEFUL);
            }
          }

          catch (libtest::fatal &e)
          {
            Error << "Fatal exception was thrown: " << e.what();
            return_code= TEST_FAILURE;
          }
          catch (std::exception &e)
          {
            Error << "Exception was thrown: " << e.what();
            return_code= TEST_FAILURE;
          }
          catch (...)
          {
            Error << "Unknown exception occurred";
            return_code= TEST_FAILURE;
          }

          stats.total++;

          switch (return_code)
          {
          case TEST_SUCCESS:
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]";
            stats.success++;
            break;

          case TEST_FAILURE:
            stats.failed++;
            failed= true;
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
            break;

          case TEST_SKIPPED:
            stats.skipped++;
            skipped= true;
            Out << "\tTesting " << run->name <<  "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
            break;

          default:
            fatal_message("invalid return code");
          }

          if (test_failed(world.on_error(return_code, creators_ptr)))
          {
            Error << "Failed while running on_error()";
            signal.set_shutdown(SHUTDOWN_GRACEFUL);
            break;
          }
        }

        (void) world.runner()->post(next->post, creators_ptr);

cleanup:
        if (failed == false and skipped == false)
        {
          stats.collection_success++;
        }

        if (failed)
        {
          stats.collection_failed++;
        }

        if (skipped)
        {
          stats.collection_skipped++;
        }

        world.shutdown(creators_ptr);
        Outn();
      }

      if (not signal.is_shutdown())
      {
        signal.set_shutdown(SHUTDOWN_GRACEFUL);
      }

      shutdown_t status= signal.get_shutdown();
      if (status == SHUTDOWN_FORCED)
      {
        Out << "Tests were aborted.";
        exit_code= EXIT_FAILURE;
      }
      else if (stats.collection_failed)
      {
        Out << "Some test failed.";
        exit_code= EXIT_FAILURE;
      }
      else if (stats.collection_skipped and stats.collection_failed and stats.collection_success)
      {
        Out << "Some tests were skipped.";
      }
      else if (stats.collection_success and stats.collection_failed == 0)
      {
        Out << "All tests completed successfully.";
      }

      stats_print(&stats);

      Outn(); // Generate a blank to break up the messages if make check/test has been run
    } while (exit_code == EXIT_SUCCESS and --opt_repeat);
  }
  catch (libtest::fatal& e)
  {
    std::cerr << e.what() << std::endl;
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  catch (...)
  {
    std::cerr << "Unknown exception halted execution." << std::endl;
  }

  return exit_code;
}
<|endoftext|>


<commit_before>#ifndef TRACE_HPP
#define TRACE_HPP

#define DO_TRACE

#if defined(DO_TRACE)

// essential macros
#define TRACE_OPEN(filename) trace_open(filename)
#define TRACE_FINISH() trace_finish()
#define TRACE_PROP(name, value) trace_prop((name), (value))
#define TRACE_VERTEX_READ(id)  trace_access(DataType::Vertex,   AccessType::Read, (id))
#define TRACE_VERTEX_RW(id)    trace_access(DataType::Vertex,   AccessType::ReadWrite, (id))
#define TRACE_VERTEX_WRITE(id) trace_access(DataType::Vertex,   AccessType::Write, (id))
#define TRACE_EDGE_READ(id)    trace_access(DataType::Edge,     AccessType::Read, (id))
#define TRACE_EDGE_WRITE(id)   trace_access(DataType::Edge,     AccessType::Write, (id))
#define TRACE_EDGE_RW(id)      trace_access(DataType::Edge,     AccessType::ReadWrite, (id))
#define TRACE_PROP_READ(id)    trace_access(DataType::Property, AccessType::Read, (id))
#define TRACE_PROP_WRITE(id)   trace_access(DataType::Property, AccessType::Write, (id))
#define TRACE_PROP_RW(id)      trace_access(DataType::Property, AccessType::ReadWrite, (id))

#include <iostream>
#include <fstream>

static std::ofstream trace_out;

static inline void trace_open(const char* filename) {
	trace_out.open(filename, std::ofstream::out);
}

static inline void trace_finish() {
	trace_out.close();
}

template<typename T>
static inline void trace_prop(const char* name, const T& value) {
	trace_out << name << "=" << value << std::endl;
}

enum class DataType   : uint8_t { Edge, Vertex, Property };
static inline const char* to_string(DataType tt) {
	switch(tt) {
	case DataType::Edge: return "E";
	case DataType::Vertex: return "V";
	case DataType::Property: return "P";
	default: return "?";
}}

enum class AccessType : uint8_t { Read, ReadWrite, Write };
static inline const char* to_string(AccessType tt) {
	switch(tt) {
	case AccessType::Read: return "r";
	case AccessType::ReadWrite: return "rw";
	case AccessType::Write: return "w";
	default: return "?";
}}
using IdType = uint64_t;
// TODO: trace address range
static inline void trace_access(DataType data, AccessType access, IdType id) {
	trace_out << to_string(data) << "," << to_string(access) << "," << id << std::endl;
}

#else

#define TRACE_OPEN(filename)
#define TRACE_FINISH()
#define TRACE_PROP(name, value)
#define TRACE_VERTEX_READ(id)
#define TRACE_VERTEX_WRITE(id)
#define TRACE_EDGE_READ(id)
#define TRACE_EDGE_WRITE(id)

#endif

// short hands / constants
#define TRACE_LOAD_GRAPH_VERTEX_COUNT(n) TRACE_PROP("vertex_count", n)
#define TRACE_LOAD_GRAPH_EDGE_COUNT(m) TRACE_PROP("edge_count", m)

#endif // TRACE_HPP
<commit_msg>[trace] add Alon's improvements<commit_after>#ifndef TRACE_HPP
#define TRACE_HPP

#define DO_TRACE

#if defined(DO_TRACE)

// essential macros
#define TRACE_OPEN(filename) trace_open(filename)
#define TRACE_FINISH() trace_finish()
#define TRACE_PROP(name, value) trace_prop((name), (value))
#define TRACE_VERTEX_READ(id,start_addr,size)       trace_access(DataType::Vertex,   AccessType::Read, (id),start_addr,size)
#define TRACE_VERTEX_RW(id,start_addr,size)         trace_access(DataType::Vertex,   AccessType::ReadWrite, (id),start_addr,size)
#define TRACE_VERTEX_WRITE(id,start_addr,size)      trace_access(DataType::Vertex,   AccessType::Write, (id),start_addr,size)
#define TRACE_EDGE_READ(id1,id2,start_addr,size)    trace_access(DataType::Edge,     AccessType::Read, id1,id2,start_addr,size)
#define TRACE_EDGE_WRITE(id1,id2,start_addr,size)   trace_access(DataType::Edge,     AccessType::Write, id1,id2,start_addr,size)
#define TRACE_EDGE_RW(id1,id2,start_addr,size)      trace_access(DataType::Edge,     AccessType::ReadWrite, id1,id2,start_addr,size)
#define TRACE_WEIGHT_READ(id1,id2,start_addr,size)  trace_access(DataType::Weight,   AccessType::Read, id1,id2,start_addr,size)
#define TRACE_WEIGHT_WRITE(id1,id2,start_addr,size) trace_access(DataType::Weight,   AccessType::Write, id1,id2,start_addr,size)
#define TRACE_WEIGHT_RW(id1,id2,start_addr,size)    trace_access(DataType::Weight,   AccessType::ReadWrite, id1,id2,start_addr,size)
#define TRACE_PROP_READ(id,start_addr,size)         trace_access(DataType::Property, AccessType::Read, (id),start_addr,size)
#define TRACE_PROP_WRITE(id,start_addr,size)        trace_access(DataType::Property, AccessType::Write, (id),start_addr,size)
#define TRACE_PROP_RW(id,start_addr,size)           trace_access(DataType::Property, AccessType::ReadWrite, (id),start_addr,size)
#define TRACE_AUX_READ(id,start_addr,size)          trace_access(DataType::Aux, AccessType::Read, (id),start_addr,size)
#define TRACE_AUX_WRITE(id,start_addr,size)         trace_access(DataType::Aux, AccessType::Write, (id),start_addr,size)
#define TRACE_AUX_RW(id,start_addr,size)            trace_access(DataType::Aux, AccessType::ReadWrite, (id),start_addr,size)

#include <iostream>
#include <fstream>

static std::ofstream trace_out;

static inline void trace_open(const char* filename) {
	trace_out.open(filename, std::ofstream::out);
}

static inline void trace_finish() {
	trace_out.close();
}

template<typename T>
static inline void trace_prop(const char* name, const T& value) {
	trace_out << name << "=" << value << std::endl;
}

enum class DataType : uint8_t { Edge, Vertex, Property, Weight, Aux };
static inline const char* to_string(DataType tt) {
	switch (tt) {
	case DataType::Edge: return "E";
	case DataType::Vertex: return "V";
	case DataType::Property: return "P";
	case DataType::Weight: return "W";
	case DataType::Aux: return "A";
	default: return "?";
	}
}

enum class AccessType : uint8_t { Read, ReadWrite, Write };
static inline const char* to_string(AccessType tt) {
	switch (tt) {
	case AccessType::Read: return "r";
	case AccessType::ReadWrite: return "rw";
	case AccessType::Write: return "w";
	default: return "?";
	}
}

typedef uint64_t IdType;
// TODO: trace address range
template<typename T>
static inline void trace_access(DataType data, AccessType access, IdType id, T* start_addr, long unsigned int size) {
	//trace_out << to_string(data) << "," << to_string(access) << "," << id << "," << start_addr << "," << size << std::endl;
	trace_out << to_string(data) << "," << id << "," << start_addr << "," << size << std::endl;
}

template<typename T>
static inline void trace_access(DataType data, AccessType access, IdType id, T* start_addr) {
	//trace_out << to_string(data) << "," << to_string(access) << "," << id << "," << start_addr << "," << size << std::endl;
	trace_out << to_string(data) << "," << id << "," << start_addr << "," << sizeof(T) << std::endl;
}

template<typename T>
static inline void trace_access(DataType data, AccessType access, IdType id1, IdType id2, T* start_addr, long unsigned int size) {
	trace_out << to_string(data) << ",<" << id1 << " " << id2 << ">," << start_addr << "," << size << std::endl;
}

#else

#define TRACE_OPEN(filename)
#define TRACE_FINISH()
#define TRACE_PROP(name, value)
#define TRACE_VERTEX_READ(id)
#define TRACE_VERTEX_WRITE(id)
#define TRACE_EDGE_READ(id)
#define TRACE_EDGE_WRITE(id)

#endif

// short hands / constants
#define TRACE_LOAD_GRAPH_VERTEX_COUNT(n) TRACE_PROP("vertex_count", n)
#define TRACE_LOAD_GRAPH_EDGE_COUNT(m) TRACE_PROP("edge_count", m)

#endif // TRACE_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_HIOP
#define MFEM_HIOP

#include "linalg.hpp"
#include "../config/config.hpp"
#include "../general/globals.hpp"

#ifdef MFEM_USE_MPI
#include "operator.hpp"
#endif

#ifdef MFEM_USE_HIOP

#include "hiopInterface.hpp"
#include "hiopNlpFormulation.hpp"

namespace mfem
{

/// Internal class - adapts the OptimizationProblem class to HiOp's interface.
class HiopOptimizationProblem : public hiop::hiopInterfaceDenseConstraints
{
private:

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

   // Problem info.
   const OptimizationProblem &problem;

   // Local and global number of variables and constraints.
   const hiop::size_type ntdofs_loc, m_total;
   hiop::size_type ntdofs_glob;

   // Initial guess.
   const Vector *x_start;

   Vector constr_vals;
   DenseMatrix constr_grads;
   bool constr_info_is_current;
   void UpdateConstrValsGrads(const Vector x);

public:
   HiopOptimizationProblem(const OptimizationProblem &prob)
      : problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(ntdofs_loc),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
#ifdef MFEM_USE_MPI
      // Used when HiOp with MPI support is called by a serial driver.
      comm = MPI_COMM_WORLD;
#endif
   }

#ifdef MFEM_USE_MPI
   HiopOptimizationProblem(const MPI_Comm& comm_,
                           const OptimizationProblem &prob)
      : comm(comm_),
        problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(0),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
      MPI_Allreduce(&ntdofs_loc, &ntdofs_glob, 1, MPI_HIOP_SIZE_TYPE, MPI_SUM, comm);
   }
#endif

   void setStartingPoint(const Vector &x0) { x_start = &x0; }

   /** Extraction of problem dimensions:
    *  n is the number of variables, m is the number of constraints. */
   virtual bool get_prob_sizes(hiop::size_type& n, hiop::size_type& m);

   /** Provide an primal starting point. This point is subject to adjustments
    *  internally in HiOp. */
   virtual bool get_starting_point(const hiop::size_type &n, double *x0);

   virtual bool get_vars_info(const hiop::size_type &n, double *xlow, double* xupp,
                              NonlinearityType* type);

   /** bounds on the constraints
    *  (clow<=-1e20 means no lower bound, cupp>=1e20 means no upper bound) */
   virtual bool get_cons_info(const hiop::size_type &m, double *clow, double *cupp,
                              NonlinearityType* type);

   /** Objective function evaluation.
    *  Each rank returns the global objective value. */
   virtual bool eval_f(const hiop::size_type &n, const double *x, bool new_x,
                       double& obj_value);

   /** Gradient of the objective function (local chunk). */
   virtual bool eval_grad_f(const hiop::size_type &n, const double *x, bool new_x,
                            double *gradf);

   /** Evaluates a subset of the constraints cons(x). The subset is of size
    *  num_cons and is described by indexes in the idx_cons array,
    *  i.e. cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1.
    *  The methods may be called multiple times, each time for a subset of the
    *  constraints, for example, for the subset containing the equalities and
    *  for the subset containing the inequalities. However, each constraint will
    *  be inquired EXACTLY once. This is done for performance considerations,
    *  to avoid temporary holders and memory copying.
    *
    *  Parameters:
    *   - n, m: the global number of variables and constraints
    *   - num_cons, idx_cons (array of size num_cons): the number and indexes of
    *     constraints to be evaluated
    *   - x: the point where the constraints are to be evaluated
    *   - new_x: whether x has been changed from the previous call to f, grad_f,
    *     or Jac
    *   - cons: array of size num_cons containing the value of the  constraints
    *     indicated by idx_cons
    *
    *  When MPI enabled, every rank populates cons, since the constraints are
    *  not distributed.
    */
   virtual bool eval_cons(const hiop::size_type &n, const hiop::size_type &m,
                          const hiop::size_type &num_cons,
                          const hiop::index_type *idx_cons,
                          const double *x, bool new_x, double *cons);

   /** Evaluates the Jacobian of the subset of constraints indicated by
    *  idx_cons. The idx_cons is assumed to be of size num_cons.
    *  Example: if cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1, then
    *  one needs to do Jac[c][j] = d cons[c] / dx_j, j = 1 .. n_loc.
    *  Jac is computed and stored in a contiguous vector (offset by rows).
    *
    *  Parameters: see eval_cons().
    *
    *  When MPI enabled, each rank computes only the local columns of the
    *  Jacobian, that is the partials with respect to local variables.
    */
   virtual bool eval_Jac_cons(const hiop::size_type &n, const hiop::size_type &m,
                              const hiop::size_type &num_cons,
                              const hiop::index_type *idx_cons,
                              const double *x, bool new_x, double *Jac);

   /** Specifies column partitioning for distributed memory vectors.
    *  Process p owns vector entries with indices cols[p] to cols[p+1]-1,
    *  where p = 0 .. nranks-1. The cols array is of size nranks + 1.
    *  Example: for a vector x of 6 entries (globally) on 3 ranks, the uniform
    *  column partitioning is cols=[0,2,4,6].
    */
   virtual bool get_vecdistrib_info(hiop::size_type global_n,
                                    hiop::index_type *cols);

#ifdef MFEM_USE_MPI
   virtual bool get_MPI_comm(MPI_Comm &comm_out)
   {
      comm_out = comm;
      return true;
   }
#endif
};

/// Adapts the HiOp functionality to the MFEM OptimizationSolver interface.
class HiopNlpOptimizer : public OptimizationSolver
{
protected:
   HiopOptimizationProblem *hiop_problem;

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

public:
   HiopNlpOptimizer();
#ifdef MFEM_USE_MPI
   HiopNlpOptimizer(MPI_Comm comm_);
#endif
   virtual ~HiopNlpOptimizer();

   virtual void SetOptimizationProblem(const OptimizationProblem &prob);

   /// Solves the optimization problem with xt as initial guess.
   virtual void Mult(const Vector &xt, Vector &x) const;
};

} // mfem namespace

#endif //MFEM_USE_HIOP
#endif //MFEM_HIOP guard
<commit_msg>Fix nvcc warnings when HiOp integration is enabled<commit_after>// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_HIOP
#define MFEM_HIOP

#include "linalg.hpp"
#include "../config/config.hpp"
#include "../general/globals.hpp"

#ifdef MFEM_USE_MPI
#include "operator.hpp"
#endif

#ifdef MFEM_USE_HIOP

#include "hiopInterface.hpp"
#include "hiopNlpFormulation.hpp"

namespace mfem
{

/// Internal class - adapts the OptimizationProblem class to HiOp's interface.
class HiopOptimizationProblem : public hiop::hiopInterfaceDenseConstraints
{
private:

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

   // Problem info.
   const OptimizationProblem &problem;

   // Local and global number of variables and constraints.
   const hiop::size_type ntdofs_loc, m_total;
   hiop::size_type ntdofs_glob;

   // Initial guess.
   const Vector *x_start;

   Vector constr_vals;
   DenseMatrix constr_grads;
   bool constr_info_is_current;
   void UpdateConstrValsGrads(const Vector x);

public:
   HiopOptimizationProblem(const OptimizationProblem &prob)
      : problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(ntdofs_loc),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
#ifdef MFEM_USE_MPI
      // Used when HiOp with MPI support is called by a serial driver.
      comm = MPI_COMM_WORLD;
#endif
   }

#ifdef MFEM_USE_MPI
   HiopOptimizationProblem(const MPI_Comm& comm_,
                           const OptimizationProblem &prob)
      : comm(comm_),
        problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(0),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
      MPI_Allreduce(&ntdofs_loc, &ntdofs_glob, 1, MPI_HIOP_SIZE_TYPE, MPI_SUM, comm);
   }
#endif

   void setStartingPoint(const Vector &x0) { x_start = &x0; }

   /** Extraction of problem dimensions:
    *  n is the number of variables, m is the number of constraints. */
   virtual bool get_prob_sizes(hiop::size_type& n, hiop::size_type& m);

   /** Provide an primal starting point. This point is subject to adjustments
    *  internally in HiOp. */
   virtual bool get_starting_point(const hiop::size_type &n, double *x0);

   using hiop::hiopInterfaceBase::get_starting_point;

   virtual bool get_vars_info(const hiop::size_type &n, double *xlow, double* xupp,
                              NonlinearityType* type);

   /** bounds on the constraints
    *  (clow<=-1e20 means no lower bound, cupp>=1e20 means no upper bound) */
   virtual bool get_cons_info(const hiop::size_type &m, double *clow, double *cupp,
                              NonlinearityType* type);

   /** Objective function evaluation.
    *  Each rank returns the global objective value. */
   virtual bool eval_f(const hiop::size_type &n, const double *x, bool new_x,
                       double& obj_value);

   /** Gradient of the objective function (local chunk). */
   virtual bool eval_grad_f(const hiop::size_type &n, const double *x, bool new_x,
                            double *gradf);

   /** Evaluates a subset of the constraints cons(x). The subset is of size
    *  num_cons and is described by indexes in the idx_cons array,
    *  i.e. cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1.
    *  The methods may be called multiple times, each time for a subset of the
    *  constraints, for example, for the subset containing the equalities and
    *  for the subset containing the inequalities. However, each constraint will
    *  be inquired EXACTLY once. This is done for performance considerations,
    *  to avoid temporary holders and memory copying.
    *
    *  Parameters:
    *   - n, m: the global number of variables and constraints
    *   - num_cons, idx_cons (array of size num_cons): the number and indexes of
    *     constraints to be evaluated
    *   - x: the point where the constraints are to be evaluated
    *   - new_x: whether x has been changed from the previous call to f, grad_f,
    *     or Jac
    *   - cons: array of size num_cons containing the value of the  constraints
    *     indicated by idx_cons
    *
    *  When MPI enabled, every rank populates cons, since the constraints are
    *  not distributed.
    */
   virtual bool eval_cons(const hiop::size_type &n, const hiop::size_type &m,
                          const hiop::size_type &num_cons,
                          const hiop::index_type *idx_cons,
                          const double *x, bool new_x, double *cons);

   using hiop::hiopInterfaceBase::eval_cons;

   /** Evaluates the Jacobian of the subset of constraints indicated by
    *  idx_cons. The idx_cons is assumed to be of size num_cons.
    *  Example: if cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1, then
    *  one needs to do Jac[c][j] = d cons[c] / dx_j, j = 1 .. n_loc.
    *  Jac is computed and stored in a contiguous vector (offset by rows).
    *
    *  Parameters: see eval_cons().
    *
    *  When MPI enabled, each rank computes only the local columns of the
    *  Jacobian, that is the partials with respect to local variables.
    */
   virtual bool eval_Jac_cons(const hiop::size_type &n, const hiop::size_type &m,
                              const hiop::size_type &num_cons,
                              const hiop::index_type *idx_cons,
                              const double *x, bool new_x, double *Jac);

   using hiop::hiopInterfaceDenseConstraints::eval_Jac_cons;

   /** Specifies column partitioning for distributed memory vectors.
    *  Process p owns vector entries with indices cols[p] to cols[p+1]-1,
    *  where p = 0 .. nranks-1. The cols array is of size nranks + 1.
    *  Example: for a vector x of 6 entries (globally) on 3 ranks, the uniform
    *  column partitioning is cols=[0,2,4,6].
    */
   virtual bool get_vecdistrib_info(hiop::size_type global_n,
                                    hiop::index_type *cols);

#ifdef MFEM_USE_MPI
   virtual bool get_MPI_comm(MPI_Comm &comm_out)
   {
      comm_out = comm;
      return true;
   }
#endif
};

/// Adapts the HiOp functionality to the MFEM OptimizationSolver interface.
class HiopNlpOptimizer : public OptimizationSolver
{
protected:
   HiopOptimizationProblem *hiop_problem;

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

public:
   HiopNlpOptimizer();
#ifdef MFEM_USE_MPI
   HiopNlpOptimizer(MPI_Comm comm_);
#endif
   virtual ~HiopNlpOptimizer();

   virtual void SetOptimizationProblem(const OptimizationProblem &prob);

   /// Solves the optimization problem with xt as initial guess.
   virtual void Mult(const Vector &xt, Vector &x) const;
};

} // mfem namespace

#endif //MFEM_USE_HIOP
#endif //MFEM_HIOP guard
<|endoftext|>


<commit_before>/** Manager for nuklear ui ***************************************************
 *                                                                           *
 * Copyright (c) 2016 Florian Oetke                                          *
 *  This file is distributed under the MIT License                           *
 *  See LICENSE file for details.                                            *
\*****************************************************************************/

#pragma once

#include <mirrage/utils/maybe.hpp>
#include <mirrage/utils/str_id.hpp>
#include <mirrage/utils/units.hpp>

#include <glm/vec2.hpp>
#include <glm/vec4.hpp>

#include <imgui.h>

#include <cstdint>
#include <memory>

namespace ImGui {
	enum class WindowPosition_X { center = 0, left = 1, right = 2 };
	enum class WindowPosition_Y { center = 0, top = 1, bottom = 2 };

	extern void PositionNextWindow(glm::vec2        size,
	                               WindowPosition_X x,
	                               WindowPosition_Y y,
	                               glm::vec2        offset = {});

	struct Column {
		const char* header = "";
		float       size   = -1.f;

		Column() = default;
		/*implicit*/ Column(const char* header, float size = -1) : header(header), size(size) {}
	};

	extern void BeginTable(const char* id,
	                       std::initializer_list<Column>,
	                       bool first_call,
	                       bool border    = true,
	                       bool separator = true);

	extern float ValueSliderFloat(const char* label,
	                              float       v,
	                              float       v_min,
	                              float       v_max,
	                              const char* format = "%.3f",
	                              float       power  = 1.0f);

	// ImGui::InputText() with std::string
	// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
	IMGUI_API bool InputText(const char*            label,
	                         std::string*           str,
	                         ImGuiInputTextFlags    flags     = 0,
	                         ImGuiInputTextCallback callback  = nullptr,
	                         void*                  user_data = nullptr);
	IMGUI_API bool InputTextMultiline(const char*            label,
	                                  std::string*           str,
	                                  const ImVec2&          size      = ImVec2(0, 0),
	                                  ImGuiInputTextFlags    flags     = 0,
	                                  ImGuiInputTextCallback callback  = nullptr,
	                                  void*                  user_data = nullptr);
	IMGUI_API bool InputTextWithHint(const char*            label,
	                                 const char*            hint,
	                                 std::string*           str,
	                                 ImGuiInputTextFlags    flags     = 0,
	                                 ImGuiInputTextCallback callback  = nullptr,
	                                 void*                  user_data = nullptr);
} // namespace ImGui

struct ImFont;

namespace mirrage {
	class Engine;

	namespace asset {
		class AID;
	}
	namespace asset {
		class Asset_manager;
	}
	namespace input {
		class Input_manager;
	}
} // namespace mirrage
namespace mirrage::gui {

	class Gui;

	namespace detail {
		struct Nk_renderer;
	}

	struct Gui_vertex {
		glm::vec2    position;
		glm::vec2    uv;
		std::uint8_t color[4];
	};

	class Gui_renderer_interface {
	  public:
		Gui_renderer_interface()          = default;
		virtual ~Gui_renderer_interface() = default;

		void draw_gui();

		virtual auto load_texture(int width, int height, int channels, const std::uint8_t* data)
		        -> std::shared_ptr<void> = 0;

		virtual auto load_texture(const asset::AID&) -> std::shared_ptr<void> = 0;

	  protected:
		friend class Gui;
		friend struct detail::Nk_renderer;

		using Prepare_data_src = std::function<void(std::uint16_t*, Gui_vertex*)>;

		virtual void prepare_draw(std::size_t      index_count,
		                          std::size_t      vertex_count,
		                          glm::mat4        view_proj,
		                          Prepare_data_src write_data)  = 0;
		virtual void draw_elements(void*         texture_handle,
		                           glm::vec4     clip_rect,
		                           std::uint32_t offset,
		                           std::uint32_t count,
		                           std::uint32_t vertex_offset) = 0;
		virtual void finalize_draw()                            = 0;

	  private:
		template <class>
		friend class Gui_renderer_instance;

		Gui* _gui;
	};

	class Gui {
	  public:
		Gui(glm::vec4 viewport, asset::Asset_manager& assets, input::Input_manager& input);
		~Gui();

		void draw();
		void start_frame();

		auto find_font(util::Str_id) const -> util::maybe<ImFont*>;

		auto viewport() const noexcept { return _viewport; }
		void viewport(glm::vec4 new_viewport);

		auto ready() const noexcept { return bool(_impl); }

		auto load_texture(const asset::AID&) -> std::shared_ptr<void>;

	  private:
		template <class>
		friend class Gui_renderer_instance;

		struct PImpl;

		glm::vec4               _viewport;
		asset::Asset_manager&   _assets;
		input::Input_manager&   _input;
		Gui_renderer_interface* _renderer = nullptr;
		std::unique_ptr<PImpl>  _impl;

		void _reset_renderer(Gui_renderer_interface*);
	};

	template <class Base>
	class Gui_renderer_instance : public Base {
		static_assert(std::is_base_of_v<Gui_renderer_interface, Base>,
		              "A gui renderer need to derive from mirrage::gui::Gui_renderer_interface!");

	  public:
		template <class... Args>
		Gui_renderer_instance(Gui& gui, Args&&... args) : Base(std::forward<Args>(args)...)
		{
			this->_gui = &gui;
			gui._reset_renderer(this);
		}
		~Gui_renderer_instance()
		{
			this->_gui->_reset_renderer(nullptr);
			this->_gui = nullptr;
		}
	};

} // namespace mirrage::gui
<commit_msg>added label `ImGui::SIZE_AUTO` for better readability of `ImVec2` with value set to zero because of auto sizing<commit_after>/** Manager for nuklear ui ***************************************************
 *                                                                           *
 * Copyright (c) 2016 Florian Oetke                                          *
 *  This file is distributed under the MIT License                           *
 *  See LICENSE file for details.                                            *
\*****************************************************************************/

#pragma once

#include <mirrage/utils/maybe.hpp>
#include <mirrage/utils/str_id.hpp>
#include <mirrage/utils/units.hpp>

#include <glm/vec2.hpp>
#include <glm/vec4.hpp>

#include <imgui.h>

#include <cstdint>
#include <memory>

namespace ImGui {
	inline constexpr float SIZE_AUTO = 0.0f;

	enum class WindowPosition_X { center = 0, left = 1, right = 2 };
	enum class WindowPosition_Y { center = 0, top = 1, bottom = 2 };

	extern void PositionNextWindow(glm::vec2        size,
	                               WindowPosition_X x,
	                               WindowPosition_Y y,
	                               glm::vec2        offset = {});

	struct Column {
		const char* header = "";
		float       size   = -1.f;

		Column() = default;
		/*implicit*/ Column(const char* header, float size = -1) : header(header), size(size) {}
	};

	extern void BeginTable(const char* id,
	                       std::initializer_list<Column>,
	                       bool first_call,
	                       bool border    = true,
	                       bool separator = true);

	extern float ValueSliderFloat(const char* label,
	                              float       v,
	                              float       v_min,
	                              float       v_max,
	                              const char* format = "%.3f",
	                              float       power  = 1.0f);

	// ImGui::InputText() with std::string
	// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
	IMGUI_API bool InputText(const char*            label,
	                         std::string*           str,
	                         ImGuiInputTextFlags    flags     = 0,
	                         ImGuiInputTextCallback callback  = nullptr,
	                         void*                  user_data = nullptr);
	IMGUI_API bool InputTextMultiline(const char*            label,
	                                  std::string*           str,
	                                  const ImVec2&          size      = ImVec2(0, 0),
	                                  ImGuiInputTextFlags    flags     = 0,
	                                  ImGuiInputTextCallback callback  = nullptr,
	                                  void*                  user_data = nullptr);
	IMGUI_API bool InputTextWithHint(const char*            label,
	                                 const char*            hint,
	                                 std::string*           str,
	                                 ImGuiInputTextFlags    flags     = 0,
	                                 ImGuiInputTextCallback callback  = nullptr,
	                                 void*                  user_data = nullptr);
} // namespace ImGui

struct ImFont;

namespace mirrage {
	class Engine;

	namespace asset {
		class AID;
	}
	namespace asset {
		class Asset_manager;
	}
	namespace input {
		class Input_manager;
	}
} // namespace mirrage
namespace mirrage::gui {

	class Gui;

	namespace detail {
		struct Nk_renderer;
	}

	struct Gui_vertex {
		glm::vec2    position;
		glm::vec2    uv;
		std::uint8_t color[4];
	};

	class Gui_renderer_interface {
	  public:
		Gui_renderer_interface()          = default;
		virtual ~Gui_renderer_interface() = default;

		void draw_gui();

		virtual auto load_texture(int width, int height, int channels, const std::uint8_t* data)
		        -> std::shared_ptr<void> = 0;

		virtual auto load_texture(const asset::AID&) -> std::shared_ptr<void> = 0;

	  protected:
		friend class Gui;
		friend struct detail::Nk_renderer;

		using Prepare_data_src = std::function<void(std::uint16_t*, Gui_vertex*)>;

		virtual void prepare_draw(std::size_t      index_count,
		                          std::size_t      vertex_count,
		                          glm::mat4        view_proj,
		                          Prepare_data_src write_data)  = 0;
		virtual void draw_elements(void*         texture_handle,
		                           glm::vec4     clip_rect,
		                           std::uint32_t offset,
		                           std::uint32_t count,
		                           std::uint32_t vertex_offset) = 0;
		virtual void finalize_draw()                            = 0;

	  private:
		template <class>
		friend class Gui_renderer_instance;

		Gui* _gui;
	};

	class Gui {
	  public:
		Gui(glm::vec4 viewport, asset::Asset_manager& assets, input::Input_manager& input);
		~Gui();

		void draw();
		void start_frame();

		auto find_font(util::Str_id) const -> util::maybe<ImFont*>;

		auto viewport() const noexcept { return _viewport; }
		void viewport(glm::vec4 new_viewport);

		auto ready() const noexcept { return bool(_impl); }

		auto load_texture(const asset::AID&) -> std::shared_ptr<void>;

	  private:
		template <class>
		friend class Gui_renderer_instance;

		struct PImpl;

		glm::vec4               _viewport;
		asset::Asset_manager&   _assets;
		input::Input_manager&   _input;
		Gui_renderer_interface* _renderer = nullptr;
		std::unique_ptr<PImpl>  _impl;

		void _reset_renderer(Gui_renderer_interface*);
	};

	template <class Base>
	class Gui_renderer_instance : public Base {
		static_assert(std::is_base_of_v<Gui_renderer_interface, Base>,
		              "A gui renderer need to derive from mirrage::gui::Gui_renderer_interface!");

	  public:
		template <class... Args>
		Gui_renderer_instance(Gui& gui, Args&&... args) : Base(std::forward<Args>(args)...)
		{
			this->_gui = &gui;
			gui._reset_renderer(this);
		}
		~Gui_renderer_instance()
		{
			this->_gui->_reset_renderer(nullptr);
			this->_gui = nullptr;
		}
	};

} // namespace mirrage::gui
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <numeric>      // std::accumulate

#include "alpr_impl.h"

#include "endtoendtest.h"

#include "detection/detectorfactory.h"
#include "support/filesystem.h"

using namespace std;
using namespace cv;
using namespace alpr;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

void outputStats(vector<double> datapoints);

int main( int argc, const char** argv )
{
  string country;
  string benchmarkName;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 5)
  {
    country = argv[1];
    benchmarkName = argv[2];
    inDir = argv[3];
    outDir = argv[4];
  }
  else
  {
    printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]);
    printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]);
    printf("\n");
    printf("\ttest names are: speed, segocr, detection\n\n" );
    return 0;
  }

  if (DirectoryExists(inDir.c_str()) == false)
  {
    printf("Input dir does not exist\n");
    return 0;
  }
  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  vector<string> files = getFilesInDir(inDir.c_str());
  sort( files.begin(), files.end(), stringCompare );

  if (benchmarkName.compare("segocr") == 0)
  {
    Config* config = new Config(country);
    config->debugOff();

    OCR* ocr = new OCR(config);

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];

        frame = imread( fullpath.c_str() );
        resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));

        Rect plateCoords;
        plateCoords.x = 0;
        plateCoords.y = 0;
        plateCoords.width = frame.cols;
        plateCoords.height = frame.rows;

	PipelineData pipeline_data(frame, plateCoords, config);

        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        CharacterAnalysis charRegion(&pipeline_data);

        if (pipeline_data.textLines.size() > 0 &&
            abs(pipeline_data.textLines[0].angle) > 4)
        {
          // Rotate image:
          Mat rotated(frame.size(), frame.type());
          Mat rot_mat( 2, 3, CV_32FC1 );
          Point center = Point( frame.cols/2, frame.rows/2 );

          rot_mat = getRotationMatrix2D( center, pipeline_data.textLines[0].angle, 1.0 );
          warpAffine( frame, rotated, rot_mat, frame.size() );

          rotated.copyTo(frame);
	  pipeline_data.crop_gray = frame;
        }

        CharacterSegmenter charSegmenter(&pipeline_data);
        ocr->performOCR(&pipeline_data);
        ocr->postProcessor.analyze(statecode, 25);

        cout << files[i] << "," << statecode << "," << ocr->postProcessor.bestChars << endl;

        imshow("Current LP", frame);
        waitKey(5);
      }
    }

    delete config;
    delete ocr;
  }
  else if (benchmarkName.compare("detection") == 0)
  {
    Config config(country);
    Detector* plateDetector = createDetector(&config);

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        frame = imread( fullpath.c_str() );

        vector<PlateRegion> regions = plateDetector->detect(frame);

        imshow("Current LP", frame);
        waitKey(5);
      }
    }

    delete plateDetector;
  }
  else if (benchmarkName.compare("speed") == 0)
  {
    // Benchmarks speed of region detection, plate analysis, and OCR

    timespec startTime;
    timespec endTime;

    Config config(country);
    config.debugOff();

    AlprImpl alpr(country);
    alpr.config->debugOff();
    alpr.setDetectRegion(true);

    Detector* plateDetector = createDetector(&config);
    StateIdentifier stateIdentifier(&config);
    OCR ocr(&config);

    vector<double> endToEndTimes;
    vector<double> regionDetectionTimes;
    vector<double> stateIdTimes;
    vector<double> lpAnalysisPositiveTimes;
    vector<double> lpAnalysisNegativeTimes;
    vector<double> ocrTimes;
    vector<double> postProcessTimes;

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        cout << "Image: " << files[i] << endl;

        string fullpath = inDir + "/" + files[i];
        frame = imread( fullpath.c_str() );

        getTime(&startTime);
        vector<Rect> regionsOfInterest;
        regionsOfInterest.push_back(Rect(0, 0, frame.cols, frame.rows));
        alpr.recognize(frame, regionsOfInterest);
        getTime(&endTime);
        double endToEndTime = diffclock(startTime, endTime);
        cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl;
        endToEndTimes.push_back(endToEndTime);

        getTime(&startTime);
        vector<PlateRegion> regions = plateDetector->detect(frame);
        getTime(&endTime);

        double regionDetectionTime = diffclock(startTime, endTime);
        cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl;
        regionDetectionTimes.push_back(regionDetectionTime);

        for (int z = 0; z < regions.size(); z++)
        {

	  PipelineData pipeline_data(frame, regions[z].rect, &config);

          getTime(&startTime);

          stateIdentifier.recognize(&pipeline_data);
          getTime(&endTime);
          double stateidTime = diffclock(startTime, endTime);
          cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
          stateIdTimes.push_back(stateidTime);

          getTime(&startTime);
          LicensePlateCandidate lp(&pipeline_data);
          lp.recognize();
          getTime(&endTime);
          double analysisTime = diffclock(startTime, endTime);
          cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;

          if (pipeline_data.plate_area_confidence > 10)
          {
            lpAnalysisPositiveTimes.push_back(analysisTime);

            getTime(&startTime);
            ocr.performOCR(&pipeline_data);
            getTime(&endTime);
            double ocrTime = diffclock(startTime, endTime);
            cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl;
            ocrTimes.push_back(ocrTime);

            getTime(&startTime);
            ocr.postProcessor.analyze("", 25);
            getTime(&endTime);
            double postProcessTime = diffclock(startTime, endTime);
            cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl;
            postProcessTimes.push_back(postProcessTime);
          }
          else
          {
            lpAnalysisNegativeTimes.push_back(analysisTime);
          }
        }

        waitKey(5);
      }
    }

    cout << endl << "---------------------" << endl;

    cout << "End to End Time Statistics:" << endl;
    outputStats(endToEndTimes);
    cout << endl;

    cout << "Region Detection Time Statistics:" << endl;
    outputStats(regionDetectionTimes);
    cout << endl;

    cout << "State ID Time Statistics:" << endl;
    outputStats(stateIdTimes);
    cout << endl;

    cout << "Positive Region Analysis Time Statistics:" << endl;
    outputStats(lpAnalysisPositiveTimes);
    cout << endl;

    cout << "Negative Region Analysis Time Statistics:" << endl;
    outputStats(lpAnalysisNegativeTimes);
    cout << endl;

    cout << "OCR Time Statistics:" << endl;
    outputStats(ocrTimes);
    cout << endl;

    cout << "Post Processing Time Statistics:" << endl;
    outputStats(postProcessTimes);
    cout << endl;
  }
  else if (benchmarkName.compare("endtoend") == 0)
  {
    EndToEndTest e2eTest(inDir, outDir);
    e2eTest.runTest(country, files);

  }
}

void outputStats(vector<double> datapoints)
{
  double sum = std::accumulate(datapoints.begin(), datapoints.end(), 0.0);
  double mean = sum / datapoints.size();

  std::vector<double> diff(datapoints.size());
  std::transform(datapoints.begin(), datapoints.end(), diff.begin(),
                 std::bind2nd(std::minus<double>(), mean));
  double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
  double stdev = std::sqrt(sq_sum / datapoints.size());

  cout << "\t" << datapoints.size() << " samples, avg: " << mean << "ms,  stdev: " << stdev << endl;
}
<commit_msg>Fixed seg and OCR benchmark using new skip_detection property<commit_after>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <numeric>      // std::accumulate

#include "alpr_impl.h"

#include "endtoendtest.h"

#include "detection/detectorfactory.h"
#include "support/filesystem.h"

using namespace std;
using namespace cv;
using namespace alpr;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

void outputStats(vector<double> datapoints);

int main( int argc, const char** argv )
{
  string country;
  string benchmarkName;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 5)
  {
    country = argv[1];
    benchmarkName = argv[2];
    inDir = argv[3];
    outDir = argv[4];
  }
  else
  {
    printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]);
    printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]);
    printf("\n");
    printf("\ttest names are: speed, segocr, detection\n\n" );
    return 0;
  }

  if (DirectoryExists(inDir.c_str()) == false)
  {
    printf("Input dir does not exist\n");
    return 0;
  }
  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  vector<string> files = getFilesInDir(inDir.c_str());
  sort( files.begin(), files.end(), stringCompare );

  if (benchmarkName.compare("segocr") == 0)
  {
    Config* config = new Config(country);
    config->debugOff();
    config->skipDetection = true;

    AlprImpl alpr(country);
    alpr.config = config;

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];

        frame = cv::imread(fullpath.c_str());

        cv::Rect roi;
        roi.x = 0;
        roi.y = 0;
        roi.width = frame.cols;
        roi.height = frame.rows;
        vector<Rect> rois;
        rois.push_back(roi);
        AlprResults results = alpr.recognize(frame, rois);

        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        if (results.plates.size() == 1)
          cout << files[i] << "," << statecode << "," << results.plates[0].bestPlate.characters << endl;
        else if (results.plates.size() == 0)
          cout << files[i] << "," << statecode << "," << endl;
        else if (results.plates.size() > 1)
          cout << files[i] << "," << statecode << ",???+" << endl;

        imshow("Current LP", frame);
        waitKey(5);
      }
    }

    delete config;
  }
  else if (benchmarkName.compare("detection") == 0)
  {
    Config config(country);
    Detector* plateDetector = createDetector(&config);

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        frame = imread( fullpath.c_str() );

        vector<PlateRegion> regions = plateDetector->detect(frame);

        imshow("Current LP", frame);
        waitKey(5);
      }
    }

    delete plateDetector;
  }
  else if (benchmarkName.compare("speed") == 0)
  {
    // Benchmarks speed of region detection, plate analysis, and OCR

    timespec startTime;
    timespec endTime;

    Config config(country);
    config.debugOff();

    AlprImpl alpr(country);
    alpr.config->debugOff();
    alpr.setDetectRegion(true);

    Detector* plateDetector = createDetector(&config);
    StateIdentifier stateIdentifier(&config);
    OCR ocr(&config);

    vector<double> endToEndTimes;
    vector<double> regionDetectionTimes;
    vector<double> stateIdTimes;
    vector<double> lpAnalysisPositiveTimes;
    vector<double> lpAnalysisNegativeTimes;
    vector<double> ocrTimes;
    vector<double> postProcessTimes;

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        cout << "Image: " << files[i] << endl;

        string fullpath = inDir + "/" + files[i];
        frame = imread( fullpath.c_str() );

        getTime(&startTime);
        vector<Rect> regionsOfInterest;
        regionsOfInterest.push_back(Rect(0, 0, frame.cols, frame.rows));
        alpr.recognize(frame, regionsOfInterest);
        getTime(&endTime);
        double endToEndTime = diffclock(startTime, endTime);
        cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl;
        endToEndTimes.push_back(endToEndTime);

        getTime(&startTime);
        vector<PlateRegion> regions = plateDetector->detect(frame);
        getTime(&endTime);

        double regionDetectionTime = diffclock(startTime, endTime);
        cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl;
        regionDetectionTimes.push_back(regionDetectionTime);

        for (int z = 0; z < regions.size(); z++)
        {

	  PipelineData pipeline_data(frame, regions[z].rect, &config);

          getTime(&startTime);

          stateIdentifier.recognize(&pipeline_data);
          getTime(&endTime);
          double stateidTime = diffclock(startTime, endTime);
          cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
          stateIdTimes.push_back(stateidTime);

          getTime(&startTime);
          LicensePlateCandidate lp(&pipeline_data);
          lp.recognize();
          getTime(&endTime);
          double analysisTime = diffclock(startTime, endTime);
          cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;

          if (pipeline_data.plate_area_confidence > 10)
          {
            lpAnalysisPositiveTimes.push_back(analysisTime);

            getTime(&startTime);
            ocr.performOCR(&pipeline_data);
            getTime(&endTime);
            double ocrTime = diffclock(startTime, endTime);
            cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl;
            ocrTimes.push_back(ocrTime);

            getTime(&startTime);
            ocr.postProcessor.analyze("", 25);
            getTime(&endTime);
            double postProcessTime = diffclock(startTime, endTime);
            cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl;
            postProcessTimes.push_back(postProcessTime);
          }
          else
          {
            lpAnalysisNegativeTimes.push_back(analysisTime);
          }
        }

        waitKey(5);
      }
    }

    cout << endl << "---------------------" << endl;

    cout << "End to End Time Statistics:" << endl;
    outputStats(endToEndTimes);
    cout << endl;

    cout << "Region Detection Time Statistics:" << endl;
    outputStats(regionDetectionTimes);
    cout << endl;

    cout << "State ID Time Statistics:" << endl;
    outputStats(stateIdTimes);
    cout << endl;

    cout << "Positive Region Analysis Time Statistics:" << endl;
    outputStats(lpAnalysisPositiveTimes);
    cout << endl;

    cout << "Negative Region Analysis Time Statistics:" << endl;
    outputStats(lpAnalysisNegativeTimes);
    cout << endl;

    cout << "OCR Time Statistics:" << endl;
    outputStats(ocrTimes);
    cout << endl;

    cout << "Post Processing Time Statistics:" << endl;
    outputStats(postProcessTimes);
    cout << endl;
  }
  else if (benchmarkName.compare("endtoend") == 0)
  {
    EndToEndTest e2eTest(inDir, outDir);
    e2eTest.runTest(country, files);

  }
}

void outputStats(vector<double> datapoints)
{
  double sum = std::accumulate(datapoints.begin(), datapoints.end(), 0.0);
  double mean = sum / datapoints.size();

  std::vector<double> diff(datapoints.size());
  std::transform(datapoints.begin(), datapoints.end(), diff.begin(),
                 std::bind2nd(std::minus<double>(), mean));
  double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
  double stdev = std::sqrt(sq_sum / datapoints.size());

  cout << "\t" << datapoints.size() << " samples, avg: " << mean << "ms,  stdev: " << stdev << endl;
}
<|endoftext|>


<commit_before>// This file was automatically generated on 24 Apr 2016 at 02:26:55

/*
	Nazara Engine - Vulkan

	Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)

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

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

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

#pragma once

#ifndef NAZARA_GLOBAL_VULKAN_HPP
#define NAZARA_GLOBAL_VULKAN_HPP

#include <Nazara/Vulkan/Config.hpp>
#include <Nazara/Vulkan/VkDevice.hpp>
#include <Nazara/Vulkan/VkInstance.hpp>
#include <Nazara/Vulkan/VkLoader.hpp>
#include <Nazara/Vulkan/Vulkan.hpp>

#endif // NAZARA_GLOBAL_VULKAN_HPP
<commit_msg>Vulkan: Update global header<commit_after>// This file was automatically generated on 15 May 2016 at 00:11:13

/*
	Nazara Engine - Vulkan

	Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)

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

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

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

#pragma once

#ifndef NAZARA_GLOBAL_VULKAN_HPP
#define NAZARA_GLOBAL_VULKAN_HPP

#include <Nazara/Vulkan/Config.hpp>
#include <Nazara/Vulkan/VkCommandBuffer.hpp>
#include <Nazara/Vulkan/VkCommandPool.hpp>
#include <Nazara/Vulkan/VkDevice.hpp>
#include <Nazara/Vulkan/VkDeviceObject.hpp>
#include <Nazara/Vulkan/VkInstance.hpp>
#include <Nazara/Vulkan/VkLoader.hpp>
#include <Nazara/Vulkan/VkSemaphore.hpp>
#include <Nazara/Vulkan/VkSurface.hpp>
#include <Nazara/Vulkan/VkSwapchain.hpp>
#include <Nazara/Vulkan/Vulkan.hpp>

#endif // NAZARA_GLOBAL_VULKAN_HPP
<|endoftext|>