<commit_before>// Copyright (c) 2012, 2013, 2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "openMVG/exif/exif_IO_EasyExif.hpp"

#include "openMVG/exif/sensor_width_database/ParseDatabase.hpp"

#include "openMVG/image/image.hpp"
#include "openMVG/stl/split.hpp"

#include "openMVG/sfm/sfm.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
#include <vector>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::exif;
using namespace openMVG::image;
using namespace openMVG::sfm;

/// Check that Kmatrix is a string like "f;0;ppx;0;f;ppy;0;0;1"
/// With f,ppx,ppy as valid numerical value
bool checkIntrinsicStringValidity(const std::string & Kmatrix, double & focal, double & ppx, double & ppy)
{
  std::vector<std::string> vec_str;
  stl::split(Kmatrix, ";", vec_str);
  if (vec_str.size() != 9)  {
    std::cerr << "\n Missing ';' character" << std::endl;
    return false;
  }
  // Check that all K matrix value are valid numbers
  for (size_t i = 0; i < vec_str.size(); ++i) {
    double readvalue = 0.0;
    std::stringstream ss;
    ss.str(vec_str[i]);
    if (! (ss >> readvalue) )  {
      std::cerr << "\n Used an invalid not a number character" << std::endl;
      return false;
    }
    if (i==0) focal = readvalue;
    if (i==2) ppx = readvalue;
    if (i==5) ppy = readvalue;
  }
  return true;
}

//
// Create the description of an input image dataset for OpenMVG toolsuite
// - Export a SfM_Data file with View & Intrinsic data
//
int main(int argc, char **argv)
{
  CmdLine cmd;

  std::string sImageDir,
    sfileDatabase = "",
    sOutputDir = "",
    sKmatrix;

  int i_User_camera_model = PINHOLE_CAMERA_RADIAL3;

  bool b_Group_camera_model = true;

  double focal_pixels = -1.0;

  cmd.add( make_option('i', sImageDir, "imageDirectory") );
  cmd.add( make_option('d', sfileDatabase, "sensorWidthDatabase") );
  cmd.add( make_option('o', sOutputDir, "outputDirectory") );
  cmd.add( make_option('f', focal_pixels, "focal") );
  cmd.add( make_option('k', sKmatrix, "intrinsics") );
  cmd.add( make_option('c', i_User_camera_model, "camera_model") );
  cmd.add( make_option('g', b_Group_camera_model, "group_camera_model") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--imageDirectory]\n"
      << "[-d|--sensorWidthDatabase]\n"
      << "[-o|--outputDirectory]\n"
      << "[-f|--focal] (pixels)\n"
      << "[-k|--intrinsics] Kmatrix: \"f;0;ppx;0;f;ppy;0;0;1\"\n"
      << "[-c|--camera_model] Camera model type:\n"
      << "\t 1: Pinhole\n"
      << "\t 2: Pinhole radial 1\n"
      << "\t 3: Pinhole radial 3 (default)\n"
      << "[-g|--group_camera_model]\n"
      << "\t 0-> each view have it's own camera intrinsic parameters,\n"
      << "\t 1-> (default) view can share some camera intrinsic parameters\n"
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  std::cout << " You called : " <<std::endl
            << argv[0] << std::endl
            << "--imageDirectory " << sImageDir << std::endl
            << "--sensorWidthDatabase " << sfileDatabase << std::endl
            << "--outputDirectory " << sOutputDir << std::endl
            << "--focal " << focal_pixels << std::endl
            << "--intrinsics " << sKmatrix << std::endl
            << "--camera_model " << i_User_camera_model << std::endl
            << "--group_camera_model " << b_Group_camera_model << std::endl;

  // Expected properties for each image
  double width = -1, height = -1, focal = -1, ppx = -1,  ppy = -1;

  const EINTRINSIC e_User_camera_model = EINTRINSIC(i_User_camera_model);

  if ( !stlplus::folder_exists( sImageDir ) )
  {
    std::cerr << "\nThe input directory doesn't exist" << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutputDir.empty())
  {
    std::cerr << "\nInvalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if ( !stlplus::folder_exists( sOutputDir ) )
  {
    if ( !stlplus::folder_create( sOutputDir ))
    {
      std::cerr << "\nCannot create output directory" << std::endl;
      return EXIT_FAILURE;
    }
  }

  if (sKmatrix.size() > 0 &&
    !checkIntrinsicStringValidity(sKmatrix, focal, ppx, ppy) )
  {
    std::cerr << "\nInvalid K matrix input" << std::endl;
    return EXIT_FAILURE;
  }

  if (sKmatrix.size() > 0 && focal_pixels != -1.0)
  {
    std::cerr << "\nCannot combine -f and -k options" << std::endl;
    return EXIT_FAILURE;
  }

  std::vector<Datasheet> vec_database;
  if (!sfileDatabase.empty())
  {
    if ( !parseDatabase( sfileDatabase, vec_database ) )
    {
      std::cerr
       << "\nInvalid input database: " << sfileDatabase
       << ", please specify a valid file." << std::endl;
      return EXIT_FAILURE;
    }
  }

  std::vector<std::string> vec_image = stlplus::folder_files( sImageDir );
  std::sort(vec_image.begin(), vec_image.end());

  // Configure an empty scene with Views and their corresponding cameras
  SfM_Data sfm_data;
  sfm_data.s_root_path = sImageDir; // Setup main image root_path
  Views & views = sfm_data.views;
  Intrinsics & intrinsics = sfm_data.intrinsics;

  for ( std::vector<std::string>::const_iterator iter_image = vec_image.begin();
    iter_image != vec_image.end();
    iter_image++ )
  {
    // Read meta data to fill camera parameter (w,h,focal,ppx,ppy) fields.
    width = height = ppx = ppy = focal = -1.0;

    const std::string sImageFilename = stlplus::create_filespec( sImageDir, *iter_image );

    // Test if the image format is supported:
    if (openMVG::image::GetFormat(sImageFilename.c_str()) == openMVG::image::Unknown)
      continue; // image cannot be opened

    ImageHeader imgHeader;
    if (!openMVG::image::ReadImageHeader(sImageFilename.c_str(), &imgHeader))
      continue; // image cannot be read

    width = imgHeader.width;
    height = imgHeader.height;
    ppx = width / 2.0;
    ppy = height / 2.0;

    std::unique_ptr<Exif_IO> exifReader(new Exif_IO_EasyExif());
    exifReader->open( sImageFilename );

    const bool bHaveValidExifMetadata =
      exifReader->doesHaveExifInfo()
      && !exifReader->getBrand().empty()
      && !exifReader->getModel().empty();

    // Consider the case where the focal is provided manually
    if ( !bHaveValidExifMetadata || focal_pixels != -1)
    {
      if (sKmatrix.size() > 0) // Known user calibration K matrix
      {
        if (!checkIntrinsicStringValidity(sKmatrix, focal, ppx, ppy))
          focal = -1.0;
      }
      else // User provided focal length value
        if (focal_pixels != -1 )
          focal = focal_pixels;
    }
    else // If image contains meta data
    {
      const std::string sCamName = exifReader->getBrand();
      const std::string sCamModel = exifReader->getModel();

      // Handle case where focal length is equal to 0
      if (exifReader->getFocal() == 0.0f)
      {
        std::cout << stlplus::basename_part(sImageFilename) << ": Focal length is missing." << std::endl;
        focal = -1.0;
      }
      else
      // Create the image entry in the list file
      {
        Datasheet datasheet;
        if ( getInfo( sCamName, sCamModel, vec_database, datasheet ))
        {
          // The camera model was found in the database so we can compute it's approximated focal length
          const double ccdw = datasheet._sensorSize;
          focal = std::max ( width, height ) * exifReader->getFocal() / ccdw;
        }
        else
        {
          std::cout << stlplus::basename_part(sImageFilename) << ": Camera \""
            << sCamName << "\" model \"" << sCamModel << "\" doesn't exist in the database" << std::endl
            << "Please consider add your camera model and sensor width in the database." << std::endl;
        }
      }
    }

    // Build intrinsic parameter related to the view
    std::shared_ptr<IntrinsicBase> intrinsic (NULL);

    if (focal > 0 && ppx > 0 && ppy > 0 && width > 0 && height > 0)
    {
      // Create the desired camera type
      switch(e_User_camera_model)
      {
        case PINHOLE_CAMERA:
          intrinsic = std::make_shared<Pinhole_Intrinsic>
            (width, height, focal, ppx, ppy);
        break;
        case PINHOLE_CAMERA_RADIAL1:
          intrinsic = std::make_shared<Pinhole_Intrinsic_Radial_K1>
            (width, height, focal, ppx, ppy, 0.0); // setup no distortion as initial guess
        break;
        case PINHOLE_CAMERA_RADIAL3:
          intrinsic = std::make_shared<Pinhole_Intrinsic_Radial_K3>
            (width, height, focal, ppx, ppy, 0.0, 0.0, 0.0);  // setup no distortion as initial guess
        break;
        default:
          std::cout << "Unknown camera model: " << (int) e_User_camera_model << std::endl;
      }
    }

    // Build the view corresponding to the image
    View v(*iter_image, views.size(), views.size(), views.size(), width, height);

    // Add intrinsic related to the image (if any)
    if (intrinsic == NULL)
    {
      //Since the view have invalid intrinsic data
      // (export the view, with an invalid intrinsic field value)
      v.id_intrinsic = UndefinedIndexT;
    }
    else
    {
      // Add the defined intrinsic to the sfm_container
      intrinsics[v.id_intrinsic] = intrinsic;
    }

    // Add the view to the sfm_container
    views[v.id_view] = std::make_shared<View>(v);
  }

  // Group camera that share common properties if desired (leads to more faster & stable BA).
  if (b_Group_camera_model)
  {
    GroupSharedIntrinsics(sfm_data);
  }

  // Store SfM_Data views & intrinsic data
  if (!Save(
    sfm_data,
    stlplus::create_filespec( sOutputDir, "sfm_data.json" ).c_str(),
    ESfM_Data(VIEWS|INTRINSICS)))
  {
    return EXIT_FAILURE;
  }

  std::cout << std::endl
    << "SfMInit_ImageListing report:\n"
    << "listed #File(s): " << vec_image.size() << "\n"
    << "usable #File(s) listed in sfm_data: " << sfm_data.GetViews().size() << std::endl;

  return EXIT_SUCCESS;
}
<commit_msg>[software] SfMInit_ImageListing. Add progress bar and enhance warning/error report. #364<commit_after>// Copyright (c) 2012, 2013, 2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "openMVG/exif/exif_IO_EasyExif.hpp"

#include "openMVG/exif/sensor_width_database/ParseDatabase.hpp"

#include "openMVG/image/image.hpp"
#include "openMVG/stl/split.hpp"

#include "openMVG/sfm/sfm.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
#include <vector>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::exif;
using namespace openMVG::image;
using namespace openMVG::sfm;

/// Check that Kmatrix is a string like "f;0;ppx;0;f;ppy;0;0;1"
/// With f,ppx,ppy as valid numerical value
bool checkIntrinsicStringValidity(const std::string & Kmatrix, double & focal, double & ppx, double & ppy)
{
  std::vector<std::string> vec_str;
  stl::split(Kmatrix, ";", vec_str);
  if (vec_str.size() != 9)  {
    std::cerr << "\n Missing ';' character" << std::endl;
    return false;
  }
  // Check that all K matrix value are valid numbers
  for (size_t i = 0; i < vec_str.size(); ++i) {
    double readvalue = 0.0;
    std::stringstream ss;
    ss.str(vec_str[i]);
    if (! (ss >> readvalue) )  {
      std::cerr << "\n Used an invalid not a number character" << std::endl;
      return false;
    }
    if (i==0) focal = readvalue;
    if (i==2) ppx = readvalue;
    if (i==5) ppy = readvalue;
  }
  return true;
}

//
// Create the description of an input image dataset for OpenMVG toolsuite
// - Export a SfM_Data file with View & Intrinsic data
//
int main(int argc, char **argv)
{
  CmdLine cmd;

  std::string sImageDir,
    sfileDatabase = "",
    sOutputDir = "",
    sKmatrix;

  int i_User_camera_model = PINHOLE_CAMERA_RADIAL3;

  bool b_Group_camera_model = true;

  double focal_pixels = -1.0;

  cmd.add( make_option('i', sImageDir, "imageDirectory") );
  cmd.add( make_option('d', sfileDatabase, "sensorWidthDatabase") );
  cmd.add( make_option('o', sOutputDir, "outputDirectory") );
  cmd.add( make_option('f', focal_pixels, "focal") );
  cmd.add( make_option('k', sKmatrix, "intrinsics") );
  cmd.add( make_option('c', i_User_camera_model, "camera_model") );
  cmd.add( make_option('g', b_Group_camera_model, "group_camera_model") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--imageDirectory]\n"
      << "[-d|--sensorWidthDatabase]\n"
      << "[-o|--outputDirectory]\n"
      << "[-f|--focal] (pixels)\n"
      << "[-k|--intrinsics] Kmatrix: \"f;0;ppx;0;f;ppy;0;0;1\"\n"
      << "[-c|--camera_model] Camera model type:\n"
      << "\t 1: Pinhole\n"
      << "\t 2: Pinhole radial 1\n"
      << "\t 3: Pinhole radial 3 (default)\n"
      << "[-g|--group_camera_model]\n"
      << "\t 0-> each view have it's own camera intrinsic parameters,\n"
      << "\t 1-> (default) view can share some camera intrinsic parameters\n"
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  std::cout << " You called : " <<std::endl
            << argv[0] << std::endl
            << "--imageDirectory " << sImageDir << std::endl
            << "--sensorWidthDatabase " << sfileDatabase << std::endl
            << "--outputDirectory " << sOutputDir << std::endl
            << "--focal " << focal_pixels << std::endl
            << "--intrinsics " << sKmatrix << std::endl
            << "--camera_model " << i_User_camera_model << std::endl
            << "--group_camera_model " << b_Group_camera_model << std::endl;

  // Expected properties for each image
  double width = -1, height = -1, focal = -1, ppx = -1,  ppy = -1;

  const EINTRINSIC e_User_camera_model = EINTRINSIC(i_User_camera_model);

  if ( !stlplus::folder_exists( sImageDir ) )
  {
    std::cerr << "\nThe input directory doesn't exist" << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutputDir.empty())
  {
    std::cerr << "\nInvalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if ( !stlplus::folder_exists( sOutputDir ) )
  {
    if ( !stlplus::folder_create( sOutputDir ))
    {
      std::cerr << "\nCannot create output directory" << std::endl;
      return EXIT_FAILURE;
    }
  }

  if (sKmatrix.size() > 0 &&
    !checkIntrinsicStringValidity(sKmatrix, focal, ppx, ppy) )
  {
    std::cerr << "\nInvalid K matrix input" << std::endl;
    return EXIT_FAILURE;
  }

  if (sKmatrix.size() > 0 && focal_pixels != -1.0)
  {
    std::cerr << "\nCannot combine -f and -k options" << std::endl;
    return EXIT_FAILURE;
  }

  std::vector<Datasheet> vec_database;
  if (!sfileDatabase.empty())
  {
    if ( !parseDatabase( sfileDatabase, vec_database ) )
    {
      std::cerr
       << "\nInvalid input database: " << sfileDatabase
       << ", please specify a valid file." << std::endl;
      return EXIT_FAILURE;
    }
  }

  std::vector<std::string> vec_image = stlplus::folder_files( sImageDir );
  std::sort(vec_image.begin(), vec_image.end());

  // Configure an empty scene with Views and their corresponding cameras
  SfM_Data sfm_data;
  sfm_data.s_root_path = sImageDir; // Setup main image root_path
  Views & views = sfm_data.views;
  Intrinsics & intrinsics = sfm_data.intrinsics;

  C_Progress_display my_progress_bar( vec_image.size(),
      std::cout, "\n- Image listing -\n" );
  std::ostringstream error_report_stream;
  for ( std::vector<std::string>::const_iterator iter_image = vec_image.begin();
    iter_image != vec_image.end();
    ++iter_image, ++my_progress_bar )
  {
    // Read meta data to fill camera parameter (w,h,focal,ppx,ppy) fields.
    width = height = ppx = ppy = focal = -1.0;

    const std::string sImageFilename = stlplus::create_filespec( sImageDir, *iter_image );

    // Test if the image format is supported:
    if (openMVG::image::GetFormat(sImageFilename.c_str()) == openMVG::image::Unknown)
      continue; // image cannot be opened

    ImageHeader imgHeader;
    if (!openMVG::image::ReadImageHeader(sImageFilename.c_str(), &imgHeader))
      continue; // image cannot be read

    width = imgHeader.width;
    height = imgHeader.height;
    ppx = width / 2.0;
    ppy = height / 2.0;

    std::unique_ptr<Exif_IO> exifReader(new Exif_IO_EasyExif());
    exifReader->open( sImageFilename );

    const bool bHaveValidExifMetadata =
      exifReader->doesHaveExifInfo()
      && !exifReader->getBrand().empty()
      && !exifReader->getModel().empty();

    // Consider the case where the focal is provided manually
    if ( !bHaveValidExifMetadata || focal_pixels != -1)
    {
      if (sKmatrix.size() > 0) // Known user calibration K matrix
      {
        if (!checkIntrinsicStringValidity(sKmatrix, focal, ppx, ppy))
          focal = -1.0;
      }
      else // User provided focal length value
        if (focal_pixels != -1 )
          focal = focal_pixels;
    }
    else // If image contains meta data
    {
      const std::string sCamName = exifReader->getBrand();
      const std::string sCamModel = exifReader->getModel();

      // Handle case where focal length is equal to 0
      if (exifReader->getFocal() == 0.0f)
      {
        error_report_stream
          << stlplus::basename_part(sImageFilename) << ": Focal length is missing." << "\n";
        focal = -1.0;
      }
      else
      // Create the image entry in the list file
      {
        Datasheet datasheet;
        if ( getInfo( sCamName, sCamModel, vec_database, datasheet ))
        {
          // The camera model was found in the database so we can compute it's approximated focal length
          const double ccdw = datasheet._sensorSize;
          focal = std::max ( width, height ) * exifReader->getFocal() / ccdw;
        }
        else
        {
          error_report_stream
            << stlplus::basename_part(sImageFilename) << ": Camera \""
            << sCamName << "\" model \"" << sCamModel << "\" doesn't exist in the database" << "\n"
            << "Please consider add your camera model and sensor width in the database." << "\n";
        }
      }
    }

    // Build intrinsic parameter related to the view
    std::shared_ptr<IntrinsicBase> intrinsic (NULL);

    if (focal > 0 && ppx > 0 && ppy > 0 && width > 0 && height > 0)
    {
      // Create the desired camera type
      switch(e_User_camera_model)
      {
        case PINHOLE_CAMERA:
          intrinsic = std::make_shared<Pinhole_Intrinsic>
            (width, height, focal, ppx, ppy);
        break;
        case PINHOLE_CAMERA_RADIAL1:
          intrinsic = std::make_shared<Pinhole_Intrinsic_Radial_K1>
            (width, height, focal, ppx, ppy, 0.0); // setup no distortion as initial guess
        break;
        case PINHOLE_CAMERA_RADIAL3:
          intrinsic = std::make_shared<Pinhole_Intrinsic_Radial_K3>
            (width, height, focal, ppx, ppy, 0.0, 0.0, 0.0);  // setup no distortion as initial guess
        break;
        default:
          std::cerr << "Error: unknown camera model: " << (int) e_User_camera_model << std::endl;
          return EXIT_FAILURE;
      }
    }

    // Build the view corresponding to the image
    View v(*iter_image, views.size(), views.size(), views.size(), width, height);

    // Add intrinsic related to the image (if any)
    if (intrinsic == NULL)
    {
      //Since the view have invalid intrinsic data
      // (export the view, with an invalid intrinsic field value)
      v.id_intrinsic = UndefinedIndexT;
    }
    else
    {
      // Add the defined intrinsic to the sfm_container
      intrinsics[v.id_intrinsic] = intrinsic;
    }

    // Add the view to the sfm_container
    views[v.id_view] = std::make_shared<View>(v);
  }

  // Display saved warning & error messages if any.
  if (!error_report_stream.str().empty())
  {
    std::cerr
      << "\nWarning & Error messages:" << std::endl
      << error_report_stream.str() << std::endl;
  }

  // Group camera that share common properties if desired (leads to more faster & stable BA).
  if (b_Group_camera_model)
  {
    GroupSharedIntrinsics(sfm_data);
  }

  // Store SfM_Data views & intrinsic data
  if (!Save(
    sfm_data,
    stlplus::create_filespec( sOutputDir, "sfm_data.json" ).c_str(),
    ESfM_Data(VIEWS|INTRINSICS)))
  {
    return EXIT_FAILURE;
  }

  std::cout << std::endl
    << "SfMInit_ImageListing report:\n"
    << "listed #File(s): " << vec_image.size() << "\n"
    << "usable #File(s) listed in sfm_data: " << sfm_data.GetViews().size() << std::endl;

  return EXIT_SUCCESS;
}
<|endoftext|>


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

#include "tasking/taskscheduler.h"
#include "tasking/taskscheduler_new.h"

#include "math/math.h"
#include "kernels/algorithms/sort.h"
#include <tbb/tbb.h>

namespace embree
{
  std::fstream fs;

  struct reduce_benchmark
  {
    reduce_benchmark()
      : N(0), array(NULL) {}

    size_t N;
    double* array;
    double threadReductions[1024];

    TASK_FUNCTION_(reduce_benchmark,reduce);

    void reduce(size_t threadIndex, size_t threadCount)
    {
      const size_t begin = (threadIndex+0)*N/threadCount;
      const size_t end   = (threadIndex+1)*N/threadCount;
      double c = 0;
      for (size_t i=begin; i<end; i++) c += sin(array[i]);
      threadReductions[threadIndex] = c;
    }

    void init(size_t N)
    {
      this->N = N;
      array = new double[N];

      for (size_t i=0; i<N; i++)
        array[i] = drand48();

    }

    double reduce_sequential(size_t N)
    {
      double sum = 0.0;
      for (size_t i=0; i<N; i++)
        sum += sin(array[i]);
      return sum;
    }

    double run_sequential (size_t N)
    {
      double t0 = getSeconds();
      double c0 = 0;
      for (size_t i=0; i<N; i++) c0 += sin(array[i]);
      volatile double result = c0;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c0) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c0 << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    double run_locksteptaskscheduler(size_t N)
    {
      double t0 = getSeconds();
      this->N = N;
      LockStepTaskScheduler* scheduler = LockStepTaskScheduler::instance();
      scheduler->dispatchTask( task_reduce, this, 0, scheduler->getNumThreads() );

      double c = 0;
      for (size_t i=0; i<scheduler->getNumThreads(); i++)
        c += threadReductions[i];
      volatile double result = c;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    double run_tbb(size_t N)
    {
      double t0 = getSeconds();
      double c2 = 0;
      //LockStepTaskScheduler::execute_tbb([&] () {
      c2 = tbb::parallel_reduce(tbb::blocked_range<size_t>(0,N,1024), 0.0,
                                [&](const tbb::blocked_range<size_t>& r, double value) -> double {
                                  double c = value;
                                  for (size_t i=r.begin(); i<r.end(); i++) c += sin(array[i]);
                                  return c;
                                },
                                std::plus<double>());
      //});
      volatile double result = c2;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c2) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c2 << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    const char* name;
  };

  template<typename Closure>
  void benchmark(size_t N0, size_t N1, const char* name, const Closure& closure)
  {
    fs << "# " << name << std::endl;
    fs << "# N dt_min dt_avg dt_max M/s(min) M/s(avg) M/s(max)" << std::endl;
    for (size_t N = N0; N < N1; N *= 1.5)
    {
      double t_min = pos_inf;
      double t_avg = 0.0f;
      double t_max = neg_inf;
      for (size_t i=0; i<10; i++)
      {
        double dt = closure(N);
        t_min = min(t_min,dt);
        if (i != 0) t_avg = t_avg + dt;
        t_max = max(t_max,dt);
      }
      t_avg /= 9.0;
      fs << N << " "
                << 1000.0f*t_min << " " << 1000.0f*t_avg << " " << 1000.0f*t_max << " "
                << 1E-6*N/t_max << " " << 1E-6*N/t_avg << " " << 1E-6*N/t_min << std::endl;
    }
  }

  reduce_benchmark reduce;

  size_t fib(size_t i)
  {
    if (i == 0)
      return 0;
    else if (i == 1)
      return 1;
    else {
      return fib(i-1) + fib(i-2);
    }
  }

  /* regression testing */
  struct task_scheduler_regression_test //: public RegressionTest
  {
    task_scheduler_regression_test(const char* name) : name(name) {
      //registerRegressionTest(this);
    }

    bool operator() (size_t N)
    {
      bool passed = true;
      printf("%s::%s ... \n",TOSTRING(isa),name);
      fflush(stdout);

      /* create task scheduler */
      TaskSchedulerNew* scheduler = new TaskSchedulerNew(8);

      struct Fib
      {
        size_t& r;
        size_t i;

        __forceinline Fib (size_t& r, size_t i) : r(r), i(i) {}

        void operator() (size_t, size_t) const
        {
          if (i < 2) {
            r = i;
          } else {
            size_t r0; const Fib fib0(r0, i-1);
            size_t r1; const Fib fib1(r1, i-2);
            TaskSchedulerNew::spawn(fib0);
            TaskSchedulerNew::spawn(fib1);
            TaskSchedulerNew::wait();
            r = r0+r1;
          }
        }
      };

      /* parallel calculation of sum of fibonacci number */
      double t0 = getSeconds();
      size_t r0 = fib(N);
      double t1 = getSeconds();
      size_t r1; Fib pfib(r1,N);
      scheduler->spawn_root(pfib);
      double t2 = getSeconds();

      printf("  sequential_fib(%zu) = %zu, %3.2fms\n",N,r0,1000.0f*(t1-t0));
      printf("  parallel_fib  (%zu) = %zu, %3.2fms\n",N,r1,1000.0f*(t2-t1));
      passed = r0 == r1;

      /* output if test passed or not */
      if (passed) printf("[passed]\n");
      else        printf("[failed]\n");

      delete scheduler;
      return passed;
    }

    const char* name;
  };

  size_t Fib(size_t n)
  {
    if (n<2) {
      return n;
    }
    else {
      size_t x, y;
      tbb::parallel_invoke([&]{x=Fib(n-1);}, [&]{y=Fib(n-2);});
      return x+y;
    }
  }

  void main()
  {
#if 1
    const size_t N = 30;
    {
      task_scheduler_regression_test task_scheduler_regression("task_scheduler_regression_test");
      task_scheduler_regression(N);
    }
    {
      tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      //tbb::task_scheduler_init init(1);
      double t0 = getSeconds();
      size_t r0 = Fib(N);
      double t1 = getSeconds();
      printf("  tbb_fib(%zu) = %zu, %3.2fms\n",N,r0,1000.0f*(t1-t0));

    }
#else

    const size_t N = 100*1024*1024;
    const size_t N_seq = 10*1024*1024;

    /* parallel reduction */
    reduce.init(N);

    fs.open ("benchmark_reduce_sequential.csv", std::fstream::out);
    benchmark(1000,N_seq,"reduce_sequential",[] (size_t N) -> double { return reduce.run_sequential(N); });
    fs.close();

    fs.open ("benchmark_reduce_lockstep.csv", std::fstream::out);
    TaskScheduler::create();
    execute_closure([&] () -> double { benchmark(1000,N,"reduce_lockstep",[] (size_t N) -> double { return reduce.run_locksteptaskscheduler(N); }); return 0.0; });
    TaskScheduler::destroy();
    fs.close();

    {
      fs.open ("benchmark_reduce_tbb.csv", std::fstream::out);
      tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      benchmark(1000,N,"reduce_tbb",[] (size_t N) -> double { return reduce.run_tbb(N); });
      fs.close();
    }

    /* parallel sort */
    int* src = new int[N];
    int* array = new int[N];
    int* temp = new int[N];
    for (size_t i=0; i<N; i++) src[i] = random<int>();
    for (size_t i=0; i<N; i++) array[i] = i;
    for (size_t i=0; i<N; i++) temp[i] = i;

    fs.open ("benchmark_sort_sequential.csv", std::fstream::out);
    benchmark(1000,N_seq,"sort_sequential",[&] (size_t N) -> double
    {
      for (size_t i=0; i<N; i++) array[i] = src[i];
      double t0 = getSeconds();
      std::sort(array,array+N);
      double t1 = getSeconds();
      //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
      return t1-t0;
    });
    fs.close();

    {
      fs.open ("benchmark_sort_tbb.csv", std::fstream::out);
      tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      benchmark(1000,N,"sort_tbb",[&] (size_t N) -> double
      {
        for (size_t i=0; i<N; i++) array[i] = src[i];
        double t0 = getSeconds();
        tbb::parallel_sort(array,array+N);
        double t1 = getSeconds();
        //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
        return t1-t0;
      });
      fs.close();
    }

    fs.open ("benchmark_sort_lockstep.csv", std::fstream::out);
    TaskScheduler::create();
    execute_closure([&] () -> double
    {
      benchmark(1000,N,"sort_lockstep",[&] (size_t N) -> double
      {
        for (size_t i=0; i<N; i++) array[i] = src[i];
        double t0 = getSeconds();
        radix_sort_u32(array,temp,N);
        double t1 = getSeconds();
        //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
        return t1-t0;
      });
      return 0.0;
    });
    TaskScheduler::destroy();
    fs.close();
#endif
  }
}

int main() {
  embree::main();
  return 0;
}

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

#include "tasking/taskscheduler.h"
#include "tasking/taskscheduler_new.h"

#include "math/math.h"
#include "kernels/algorithms/sort.h"
#include <tbb/tbb.h>

namespace embree
{
  std::fstream fs;

  struct reduce_benchmark
  {
    reduce_benchmark()
      : N(0), array(NULL) {}

    size_t N;
    double* array;
    double threadReductions[1024];

    TASK_FUNCTION_(reduce_benchmark,reduce);

    void reduce(size_t threadIndex, size_t threadCount)
    {
      const size_t begin = (threadIndex+0)*N/threadCount;
      const size_t end   = (threadIndex+1)*N/threadCount;
      double c = 0;
      for (size_t i=begin; i<end; i++) c += sin(array[i]);
      threadReductions[threadIndex] = c;
    }

    void init(size_t N)
    {
      this->N = N;
      array = new double[N];

      for (size_t i=0; i<N; i++)
        array[i] = drand48();

    }

    double reduce_sequential(size_t N)
    {
      double sum = 0.0;
      for (size_t i=0; i<N; i++)
        sum += sin(array[i]);
      return sum;
    }

    double run_sequential (size_t N)
    {
      double t0 = getSeconds();
      double c0 = 0;
      for (size_t i=0; i<N; i++) c0 += sin(array[i]);
      volatile double result = c0;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c0) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c0 << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    double run_locksteptaskscheduler(size_t N)
    {
      double t0 = getSeconds();
      this->N = N;
      LockStepTaskScheduler* scheduler = LockStepTaskScheduler::instance();
      scheduler->dispatchTask( task_reduce, this, 0, scheduler->getNumThreads() );

      double c = 0;
      for (size_t i=0; i<scheduler->getNumThreads(); i++)
        c += threadReductions[i];
      volatile double result = c;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    double run_tbb(size_t N)
    {
      double t0 = getSeconds();
      double c2 = 0;
      //LockStepTaskScheduler::execute_tbb([&] () {
      c2 = tbb::parallel_reduce(tbb::blocked_range<size_t>(0,N,1024), 0.0,
                                [&](const tbb::blocked_range<size_t>& r, double value) -> double {
                                  double c = value;
                                  for (size_t i=r.begin(); i<r.end(); i++) c += sin(array[i]);
                                  return c;
                                },
                                std::plus<double>());
      //});
      volatile double result = c2;
      double t1 = getSeconds();

      /*double sum = reduce_sequential(N);
      if (abs(sum-c2) > 1E-5) {
        std::cerr << "internal error: " << sum << " != " << c2 << std::endl;
        exit(1);
        }*/
      return t1-t0;
    }

    const char* name;
  };

  template<typename Closure>
  void benchmark(size_t N0, size_t N1, const char* name, const Closure& closure)
  {
    fs << "# " << name << std::endl;
    fs << "# N dt_min dt_avg dt_max M/s(min) M/s(avg) M/s(max)" << std::endl;
    for (size_t N = N0; N < N1; N *= 1.5)
    {
      double t_min = pos_inf;
      double t_avg = 0.0f;
      double t_max = neg_inf;
      for (size_t i=0; i<10; i++)
      {
        double dt = closure(N);
        t_min = min(t_min,dt);
        if (i != 0) t_avg = t_avg + dt;
        t_max = max(t_max,dt);
      }
      t_avg /= 9.0;
      fs << N << " "
                << 1000.0f*t_min << " " << 1000.0f*t_avg << " " << 1000.0f*t_max << " "
                << 1E-6*N/t_max << " " << 1E-6*N/t_avg << " " << 1E-6*N/t_min << std::endl;
    }
  }

  reduce_benchmark reduce;

  const int CUTOFF = 20;

  size_t fib(size_t i)
  {
    if (i == 0)
      return 0;
    else if (i == 1)
      return 1;
    else {
      return fib(i-1) + fib(i-2);
    }
  }

  /* regression testing */
  struct task_scheduler_regression_test //: public RegressionTest
  {
    task_scheduler_regression_test(const char* name) : name(name) {
      //registerRegressionTest(this);
    }

    bool operator() (size_t N)
    {
      bool passed = true;
      printf("%s::%s ... \n",TOSTRING(isa),name);
      fflush(stdout);

      /* create task scheduler */
      TaskSchedulerNew* scheduler = new TaskSchedulerNew(8);

      struct Fib
      {
        size_t& r;
        size_t i;

        __forceinline Fib (size_t& r, size_t i) : r(r), i(i) {}

        void operator() (size_t, size_t) const
        {
          if (i < CUTOFF) {
            r = fib(i); //i;
          } else {
            size_t r0; const Fib fib0(r0, i-1);
            size_t r1; const Fib fib1(r1, i-2);
            TaskSchedulerNew::spawn(fib0);
            TaskSchedulerNew::spawn(fib1);
            TaskSchedulerNew::wait();
            r = r0+r1;
          }
        }
      };

      /* parallel calculation of sum of fibonacci number */
      double t0 = getSeconds();
      size_t r0 = fib(N);
      double t1 = getSeconds();
      size_t r1; Fib pfib(r1,N);
      scheduler->spawn_root(pfib);
      double t2 = getSeconds();

      printf("  sequential_fib(%zu) = %zu, %3.2fms\n",N,r0,1000.0f*(t1-t0));
      printf("  parallel_fib  (%zu) = %zu, %3.2fms\n",N,r1,1000.0f*(t2-t1));
      passed = r0 == r1;

      /* output if test passed or not */
      if (passed) printf("[passed]\n");
      else        printf("[failed]\n");

      delete scheduler;
      return passed;
    }

    const char* name;
  };

  size_t Fib(size_t n)
  {
    if (n<CUTOFF) {
      return fib(n);
    }
    else {
      size_t x, y;
      //for (volatile size_t i=0; ; i++);
      tbb::parallel_invoke([&]{x=Fib(n-1);}, [&]{y=Fib(n-2);});
      //if (n == 40) *((char*)NULL) = 0;
      return x+y;
    }
  }

  struct myobserver : public tbb::task_scheduler_observer
  {
    virtual void on_scheduler_entry( bool is_worker ) {
      PRINT("on_scheduler_entry");
    }
    virtual void on_scheduler_exit( bool is_worker ) {
      PRINT("on_scheduler_exit");
    }
  };

  void main()
  {
#if 0
    const size_t N = 40;
    //tbb::task_arena limited(2);
    //limited.my_limit = 1000000;

    /*{
      task_scheduler_regression_test task_scheduler_regression("task_scheduler_regression_test");
      task_scheduler_regression(N);
      }*/
    {
      //tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      tbb::task_scheduler_init init(8);
      myobserver observer; observer.observe();
      double t0 = getSeconds();
      size_t r0 = Fib(N);
      double t1 = getSeconds();
      //sleep(1);
      //*((char*)NULL) = 0;
      //Fib(N);
      printf("  tbb_fib(%zu) = %zu, %3.2fms\n",N,r0,1000.0f*(t1-t0));

    }
#else

    const size_t N = 100*1024*1024;
    const size_t N_seq = 10*1024*1024;

    /* parallel reduction */
    reduce.init(N);

    fs.open ("benchmark_reduce_sequential.csv", std::fstream::out);
    benchmark(1000,N_seq,"reduce_sequential",[] (size_t N) -> double { return reduce.run_sequential(N); });
    fs.close();

    fs.open ("benchmark_reduce_lockstep.csv", std::fstream::out);
    TaskScheduler::create();
    execute_closure([&] () -> double { benchmark(1000,N,"reduce_lockstep",[] (size_t N) -> double { return reduce.run_locksteptaskscheduler(N); }); return 0.0; });
    TaskScheduler::destroy();
    fs.close();

    {
      fs.open ("benchmark_reduce_tbb.csv", std::fstream::out);
      tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      benchmark(1000,N,"reduce_tbb",[] (size_t N) -> double { return reduce.run_tbb(N); });
      fs.close();
    }

    /* parallel sort */
    int* src = new int[N];
    int* array = new int[N];
    int* temp = new int[N];
    for (size_t i=0; i<N; i++) src[i] = random<int>();
    for (size_t i=0; i<N; i++) array[i] = i;
    for (size_t i=0; i<N; i++) temp[i] = i;

    fs.open ("benchmark_sort_sequential.csv", std::fstream::out);
    benchmark(1000,N_seq,"sort_sequential",[&] (size_t N) -> double
    {
      for (size_t i=0; i<N; i++) array[i] = src[i];
      double t0 = getSeconds();
      std::sort(array,array+N);
      double t1 = getSeconds();
      //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
      return t1-t0;
    });
    fs.close();

    {
      fs.open ("benchmark_sort_tbb.csv", std::fstream::out);
      tbb::task_scheduler_init init(tbb::task_scheduler_init::default_num_threads());
      benchmark(1000,N,"sort_tbb",[&] (size_t N) -> double
      {
        for (size_t i=0; i<N; i++) array[i] = src[i];
        double t0 = getSeconds();
        tbb::parallel_sort(array,array+N);
        double t1 = getSeconds();
        //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
        return t1-t0;
      });
      fs.close();
    }

    fs.open ("benchmark_sort_lockstep.csv", std::fstream::out);
    TaskScheduler::create();
    execute_closure([&] () -> double
    {
      benchmark(1000,N,"sort_lockstep",[&] (size_t N) -> double
      {
        for (size_t i=0; i<N; i++) array[i] = src[i];
        double t0 = getSeconds();
        radix_sort_u32(array,temp,N);
        double t1 = getSeconds();
        //for (size_t i=1; i<N; i++) if (array[i] < array[i-1]) { std::cerr << "internal error" << std::endl;  exit(1); }
        return t1-t0;
      });
      return 0.0;
    });
    TaskScheduler::destroy();
    fs.close();
#endif
  }
}

int main() {
  embree::main();
  return 0;
}

<|endoftext|>


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

#define CATCH_CONFIG_ENABLE_BENCHMARKING

#include "util/test_file.hpp"
#include "util/test_utils.hpp"

#include "impl/object_accessor_impl.hpp"
#include "impl/realm_coordinator.hpp"
#include "binding_context.hpp"
#include "object_schema.hpp"
#include "property.hpp"
#include "results.hpp"
#include "schema.hpp"

#include <realm/db.hpp>
#include <realm/query_engine.hpp>
#include <realm/query_expression.hpp>

using namespace realm;

struct TestContext : CppContext {
    std::map<std::string, AnyDict> defaults;

    using CppContext::CppContext;
    TestContext(TestContext& parent, realm::Property const& prop)
    : CppContext(parent, prop)
    , defaults(parent.defaults)
    { }

    util::Optional<util::Any>
    default_value_for_property(ObjectSchema const& object, Property const& prop)
    {
        auto obj_it = defaults.find(object.name);
        if (obj_it == defaults.end())
            return util::none;
        auto prop_it = obj_it->second.find(prop.name);
        if (prop_it == obj_it->second.end())
            return util::none;
        return prop_it->second;
    }

    void will_change(Object const&, Property const&) {}
    void did_change() {}
    std::string print(util::Any) { return "not implemented"; }
    bool allow_missing(util::Any) { return false; }
};

TEST_CASE("Benchmark object", "[benchmark]") {
    using namespace std::string_literals;
    using AnyVec = std::vector<util::Any>;
    using AnyDict = std::map<std::string, util::Any>;
    _impl::RealmCoordinator::assert_no_open_realms();

    InMemoryTestFile config;
    config.automatic_change_notifications = false;
    config.schema = Schema{
        {"all types", {
            {"pk", PropertyType::Int, Property::IsPrimary{true}},
            {"bool", PropertyType::Bool},
            {"int", PropertyType::Int},
            {"float", PropertyType::Float},
            {"double", PropertyType::Double},
            {"string", PropertyType::String},
            {"data", PropertyType::Data},
            {"date", PropertyType::Date},
            {"object", PropertyType::Object|PropertyType::Nullable, "link target"},

            {"bool array", PropertyType::Array|PropertyType::Bool},
            {"int array", PropertyType::Array|PropertyType::Int},
            {"float array", PropertyType::Array|PropertyType::Float},
            {"double array", PropertyType::Array|PropertyType::Double},
            {"string array", PropertyType::Array|PropertyType::String},
            {"data array", PropertyType::Array|PropertyType::Data},
            {"date array", PropertyType::Array|PropertyType::Date},
            {"object array", PropertyType::Array|PropertyType::Object, "array target"},
        }},
        {"link target", {
            {"value", PropertyType::Int},
        }, {
            {"origin", PropertyType::LinkingObjects|PropertyType::Array, "all types", "object"},
        }},
        {"array target", {
            {"value", PropertyType::Int},
        }},
        {"person", {
            {"name", PropertyType::String, Property::IsPrimary{true}},
            {"age", PropertyType::Int},
            {"scores", PropertyType::Array|PropertyType::Int},
            {"assistant", PropertyType::Object|PropertyType::Nullable, "person"},
            {"team", PropertyType::Array|PropertyType::Object, "person"},
        }},
    };

    config.schema_version = 0;
    auto r = Realm::get_shared_realm(config);
    TestContext d(r);

    auto create_person = [&](util::Any&& value, bool update, bool update_only_diff = false) {
        r->begin_transaction();
        auto obj = Object::create(d, r, *r->schema().find("person"), value, update, update_only_diff);
        r->commit_transaction();
        return obj;
    };

    SECTION("create object") {
        r->begin_transaction();
        ObjectSchema all_types = *r->schema().find("all types");
        constexpr bool update = false;
        constexpr bool update_only_diff = false;

        int64_t benchmark_pk = 0;
        BENCHMARK("create object") {
            return Object::create(d, r, all_types, util::Any(AnyDict{
                {"pk", benchmark_pk++},
                {"bool", true},
                {"int", INT64_C(5)},
                {"float", 2.2f},
                {"double", 3.3},
                {"string", "hello"s},
                {"data", "olleh"s},
                {"date", Timestamp(10, 20)},
                {"object", AnyDict{{"value", INT64_C(10)}}},

                {"bool array", AnyVec{true, false}},
                {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
                {"float array", AnyVec{1.1f, 2.2f}},
                {"double array", AnyVec{3.3, 4.4}},
                {"string array", AnyVec{"a"s, "b"s, "c"s}},
                {"data array", AnyVec{"d"s, "e"s, "f"s}},
                {"date array", AnyVec{}},
                {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
            }), update, update_only_diff);
        };
        r->commit_transaction();
    }

    SECTION("update object") {
        auto table = r->read_group().get_table("class_all types");
        r->begin_transaction();
        ObjectSchema all_types = *r->schema().find("all types");
        constexpr bool update = false;
        constexpr bool update_only_diff = false;
        auto obj = Object::create(d, r, all_types, util::Any(AnyDict{
            {"pk", INT64_C(0)},
            {"bool", true},
            {"int", INT64_C(5)},
            {"float", 2.2f},
            {"double", 3.3},
            {"string", "hello"s},
            {"data", "olleh"s},
            {"date", Timestamp(10, 20)},
            {"object", AnyDict{{"value", INT64_C(10)}}},

            {"bool array", AnyVec{true, false}},
            {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
            {"float array", AnyVec{1.1f, 2.2f}},
            {"double array", AnyVec{3.3, 4.4}},
            {"string array", AnyVec{"a"s, "b"s, "c"s}},
            {"data array", AnyVec{"d"s, "e"s, "f"s}},
            {"date array", AnyVec{}},
            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
        }), update, update_only_diff);
        r->commit_transaction();

        Results result(r, *table);
        size_t num_modifications = 0;
        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
            num_modifications += c.modifications.count();
        });

        advance_and_notify(*r);
        int64_t update_int = 1;
        ColKey col_int = table->get_column_key("int");
        REQUIRE(col_int);
        BENCHMARK_ADVANCED("update object")(Catch::Benchmark::Chronometer meter) {
            r->begin_transaction();
            meter.measure([&d, &all_types, &update_int, &r] {
                auto shadow = Object::create(d, r, all_types, util::Any(AnyDict{
                    {"pk", INT64_C(0)},
                    {"int", update_int},
                }), true, true);
            });
            r->commit_transaction();
            advance_and_notify(*r);
            REQUIRE(result.size() == 1);
            REQUIRE(result.get(0).get<Int>(col_int) == update_int);
            update_int++;
        };
    }

    SECTION("change notifications reporting") {
        auto table = r->read_group().get_table("class_person");
        Results result(r, *table);
        size_t num_calls = 0;
        size_t num_insertions = 0;
        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
            num_insertions += c.insertions.count();
            ++num_calls;
        });

        advance_and_notify(*r);
        int64_t pk = 0;
        BENCHMARK_ADVANCED("create notifications")(Catch::Benchmark::Chronometer meter) {
            std::stringstream name;
            name << "person_" << pk++;
            AnyDict person {
                {"name", name.str()},
                {"age", pk},
            };
            create_person(person, true, false);
            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(static_cast<int64_t>(num_calls) == pk + 1);
            REQUIRE(static_cast<int64_t>(num_insertions) == pk);
        };
    }
}

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

#define CATCH_CONFIG_ENABLE_BENCHMARKING

#include "util/index_helpers.hpp"
#include "util/test_file.hpp"
#include "util/test_utils.hpp"

#include "impl/object_accessor_impl.hpp"
#include "impl/realm_coordinator.hpp"
#include "binding_context.hpp"
#include "object_schema.hpp"
#include "property.hpp"
#include "results.hpp"
#include "schema.hpp"

#include <realm/db.hpp>
#include <realm/query_engine.hpp>
#include <realm/query_expression.hpp>

using namespace realm;

struct TestContext : CppContext {
    std::map<std::string, AnyDict> defaults;

    using CppContext::CppContext;
    TestContext(TestContext& parent, realm::Property const& prop)
    : CppContext(parent, prop)
    , defaults(parent.defaults)
    { }

    util::Optional<util::Any>
    default_value_for_property(ObjectSchema const& object, Property const& prop)
    {
        auto obj_it = defaults.find(object.name);
        if (obj_it == defaults.end())
            return util::none;
        auto prop_it = obj_it->second.find(prop.name);
        if (prop_it == obj_it->second.end())
            return util::none;
        return prop_it->second;
    }

    void will_change(Object const&, Property const&) {}
    void did_change() {}
    std::string print(util::Any) { return "not implemented"; }
    bool allow_missing(util::Any) { return false; }
};

TEST_CASE("Benchmark index change calculations", "[benchmark]") {
    _impl::CollectionChangeBuilder c;

    auto all_modified = [](size_t) { return true; };
    auto none_modified = [](size_t) { return false; };

    SECTION("reports inserts/deletes for simple reorderings") {
        auto calc = [&](std::vector<int64_t> old_rows, std::vector<int64_t> new_rows, std::function<bool (size_t)> modifications) {
            return _impl::CollectionChangeBuilder::calculate(old_rows, new_rows, modifications);
        };
        std::vector<int64_t> indices = {};
        constexpr size_t indices_size = 10000;
        indices.reserve(indices_size);
        for (size_t i = 0; i < indices_size; ++i) {
            indices.push_back(i);
        }

        BENCHMARK("no changes") {
            c = calc(indices, indices, none_modified);
        };
        REQUIRE(c.insertions.empty());
        REQUIRE(c.deletions.empty());

        BENCHMARK("all modified") {
            c = calc(indices, indices, all_modified);
        };
        REQUIRE(c.insertions.empty());
        REQUIRE(c.deletions.empty());

        BENCHMARK("calc 1") {
            c = calc({1, 2, 3}, {1, 3, 2}, none_modified);
        };
        REQUIRE_INDICES(c.insertions, 1);
        REQUIRE_INDICES(c.deletions, 2);

        BENCHMARK("calc 2") {
            c = calc({1, 2, 3}, {2, 1, 3}, none_modified);
        };
        REQUIRE_INDICES(c.insertions, 0);
        REQUIRE_INDICES(c.deletions, 1);

        BENCHMARK("calc 3") {
            c = calc({1, 2, 3}, {2, 3, 1}, none_modified);
        };
        REQUIRE_INDICES(c.insertions, 2);
        REQUIRE_INDICES(c.deletions, 0);

        BENCHMARK("calc 4") {
            c = calc({1, 2, 3}, {3, 1, 2}, none_modified);
        };
        REQUIRE_INDICES(c.insertions, 0);
        REQUIRE_INDICES(c.deletions, 2);

        BENCHMARK("calc 5") {
            c = calc({1, 2, 3}, {3, 2, 1}, none_modified);
        };
        REQUIRE_INDICES(c.insertions, 0, 1);
        REQUIRE_INDICES(c.deletions, 1, 2);
    }
}

TEST_CASE("Benchmark object", "[benchmark]") {
    using namespace std::string_literals;
    using AnyVec = std::vector<util::Any>;
    using AnyDict = std::map<std::string, util::Any>;
    _impl::RealmCoordinator::assert_no_open_realms();

    InMemoryTestFile config;
    config.automatic_change_notifications = false;
    config.schema = Schema{
        {"all types", {
            {"pk", PropertyType::Int, Property::IsPrimary{true}},
            {"bool", PropertyType::Bool},
            {"int", PropertyType::Int},
            {"float", PropertyType::Float},
            {"double", PropertyType::Double},
            {"string", PropertyType::String},
            {"data", PropertyType::Data},
            {"date", PropertyType::Date},
            {"object", PropertyType::Object|PropertyType::Nullable, "link target"},

            {"bool array", PropertyType::Array|PropertyType::Bool},
            {"int array", PropertyType::Array|PropertyType::Int},
            {"float array", PropertyType::Array|PropertyType::Float},
            {"double array", PropertyType::Array|PropertyType::Double},
            {"string array", PropertyType::Array|PropertyType::String},
            {"data array", PropertyType::Array|PropertyType::Data},
            {"date array", PropertyType::Array|PropertyType::Date},
            {"object array", PropertyType::Array|PropertyType::Object, "array target"},
        }},
        {"link target", {
            {"value", PropertyType::Int},
        }, {
            {"origin", PropertyType::LinkingObjects|PropertyType::Array, "all types", "object"},
        }},
        {"array target", {
            {"value", PropertyType::Int},
        }},
        {"person", {
            {"name", PropertyType::String, Property::IsPrimary{true}},
            {"age", PropertyType::Int},
            {"scores", PropertyType::Array|PropertyType::Int},
            {"assistant", PropertyType::Object|PropertyType::Nullable, "person"},
            {"team", PropertyType::Array|PropertyType::Object, "person"},
        }},
    };

    config.schema_version = 0;
    auto r = Realm::get_shared_realm(config);
    TestContext d(r);

    SECTION("create object") {
        r->begin_transaction();
        ObjectSchema all_types = *r->schema().find("all types");
        constexpr bool update = false;
        constexpr bool update_only_diff = false;

        int64_t benchmark_pk = 0;
        BENCHMARK("create object") {
            return Object::create(d, r, all_types, util::Any(AnyDict{
                {"pk", benchmark_pk++},
                {"bool", true},
                {"int", INT64_C(5)},
                {"float", 2.2f},
                {"double", 3.3},
                {"string", "hello"s},
                {"data", "olleh"s},
                {"date", Timestamp(10, 20)},
                {"object", AnyDict{{"value", INT64_C(10)}}},

                {"bool array", AnyVec{true, false}},
                {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
                {"float array", AnyVec{1.1f, 2.2f}},
                {"double array", AnyVec{3.3, 4.4}},
                {"string array", AnyVec{"a"s, "b"s, "c"s}},
                {"data array", AnyVec{"d"s, "e"s, "f"s}},
                {"date array", AnyVec{}},
                {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
            }), update, update_only_diff);
        };
        r->commit_transaction();
    }

    SECTION("update object") {
        auto table = r->read_group().get_table("class_all types");
        r->begin_transaction();
        ObjectSchema all_types = *r->schema().find("all types");
        constexpr bool update = false;
        constexpr bool update_only_diff = false;
        auto obj = Object::create(d, r, all_types, util::Any(AnyDict{
            {"pk", INT64_C(0)},
            {"bool", true},
            {"int", INT64_C(5)},
            {"float", 2.2f},
            {"double", 3.3},
            {"string", "hello"s},
            {"data", "olleh"s},
            {"date", Timestamp(10, 20)},
            {"object", AnyDict{{"value", INT64_C(10)}}},

            {"bool array", AnyVec{true, false}},
            {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
            {"float array", AnyVec{1.1f, 2.2f}},
            {"double array", AnyVec{3.3, 4.4}},
            {"string array", AnyVec{"a"s, "b"s, "c"s}},
            {"data array", AnyVec{"d"s, "e"s, "f"s}},
            {"date array", AnyVec{}},
            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
        }), update, update_only_diff);
        r->commit_transaction();

        Results result(r, *table);
        size_t num_modifications = 0;
        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
            num_modifications += c.modifications.count();
        });

        advance_and_notify(*r);
        int64_t update_int = 1;
        ColKey col_int = table->get_column_key("int");
        REQUIRE(col_int);
        BENCHMARK_ADVANCED("update object")(Catch::Benchmark::Chronometer meter) {
            r->begin_transaction();
            meter.measure([&d, &all_types, &update_int, &r] {
                auto shadow = Object::create(d, r, all_types, util::Any(AnyDict{
                    {"pk", INT64_C(0)},
                    {"int", update_int},
                }), true, true);
            });
            r->commit_transaction();
            advance_and_notify(*r);
            REQUIRE(result.size() == 1);
            REQUIRE(result.get(0).get<Int>(col_int) == update_int);
            update_int++;
        };
    }

    SECTION("change notifications reporting") {
        auto table = r->read_group().get_table("class_person");
        Results result(r, *table);
        size_t num_calls = 0;
        size_t num_insertions = 0;
        size_t num_deletions = 0;
        size_t num_modifications = 0;
        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
            num_insertions += c.insertions.count();
            num_deletions += c.deletions.count();
            num_modifications += c.modifications_new.count();
            ++num_calls;
        });

        advance_and_notify(*r);
        int64_t pk = 0;
        ObjectSchema person_schema = *r->schema().find("person");
        constexpr size_t num_objects = 100;
        constexpr bool update = false;
        constexpr bool update_only_diff = false;

        BENCHMARK_ADVANCED("create notifications")(Catch::Benchmark::Chronometer meter) {
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);
            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                std::stringstream name;
                name << "person_" << i;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(i)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();
            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == num_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == 0);
            REQUIRE(result.size() == num_objects);
        };

        r->begin_transaction();
        result.clear();
        r->commit_transaction();
        advance_and_notify(*r);
        pk = 0;
        num_calls = 0;

        BENCHMARK_ADVANCED("delete notifications")(Catch::Benchmark::Chronometer meter) {
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);
            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                std::stringstream name;
                name << "person_" << i;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(i)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();
            advance_and_notify(*r);
            REQUIRE(num_insertions == num_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == 0);
            REQUIRE(result.size() == num_objects);

            r->begin_transaction();
            result.clear();
            r->commit_transaction();

            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == num_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == num_objects);
            REQUIRE(result.size() == 0);
        };

        BENCHMARK_ADVANCED("modify notifications")(Catch::Benchmark::Chronometer meter) {
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);
            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                std::stringstream name;
                name << "person_" << i;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(i)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();
            advance_and_notify(*r);
            REQUIRE(result.size() == num_objects);
            REQUIRE(num_insertions == num_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == 0);
            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                std::stringstream name;
                name << "person_" << i;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(i + 1)}, // age differs
                };
                constexpr bool do_update = true;
                Object::create(d, r, person_schema, Any(person), do_update, update_only_diff);
            }
            r->commit_transaction();

            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == 0);
            REQUIRE(num_modifications == num_objects);
            REQUIRE(num_deletions == 0);
            REQUIRE(result.size() == num_objects);
        };
    }

    SECTION("change notifications sorted") {
        auto table = r->read_group().get_table("class_person");
        auto age_col = table->get_column_key("age");
        Results result = Results(r, *table).sort({{"age", true}});
        size_t num_insertions = 0;
        size_t num_deletions = 0;
        size_t num_modifications = 0;
        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
            num_insertions += c.insertions.count();
            num_deletions += c.deletions.count();
            num_modifications += c.modifications_new.count();
        });

        advance_and_notify(*r);
        ObjectSchema person_schema = *r->schema().find("person");
        constexpr bool update = false;
        constexpr bool update_only_diff = false;
        auto add_objects = [&](size_t num_objects, size_t start_index = 0) {
            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                size_t index = i + start_index;
                std::stringstream name;
                name << "person_" << index;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(index)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();
        };

        BENCHMARK_ADVANCED("prepend insertions")(Catch::Benchmark::Chronometer meter) {
            constexpr size_t num_initial_objects = 100;
            constexpr size_t num_prepend_objects = 100;
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);
            add_objects(num_initial_objects, num_prepend_objects);
            advance_and_notify(*r);

            add_objects(num_prepend_objects, 0);

            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == num_prepend_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == 0);
            REQUIRE(result.size() == num_prepend_objects + num_initial_objects);
            REQUIRE(result.get(0).get<int64_t>(age_col) == 0);
            REQUIRE(result.get(result.size() - 1).get<int64_t>(age_col) == num_prepend_objects + num_initial_objects - 1);
        };

        BENCHMARK_ADVANCED("insert even, insert odd")(Catch::Benchmark::Chronometer meter) {
            constexpr size_t num_objects = 100;
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);

            // insert even
            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                size_t index = i * 2;
                std::stringstream name;
                name << "person_" << index;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(index)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();
            advance_and_notify(*r);

            // insert odd
            r->begin_transaction();
            for (size_t i = 0; i < num_objects; ++i) {
                size_t index = i * 2 + 1;
                std::stringstream name;
                name << "person_" << index;
                AnyDict person {
                    {"name", name.str()},
                    {"age", static_cast<int64_t>(index)},
                };
                Object::create(d, r, person_schema, Any(person), update, update_only_diff);
            }
            r->commit_transaction();

            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == num_objects);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == 0);
            REQUIRE(result.size() == num_objects * 2);
            REQUIRE(result.get(0).get<int64_t>(age_col) == 0);
            REQUIRE(result.get(1).get<int64_t>(age_col) == 1);
            REQUIRE(result.get(result.size() - 1).get<int64_t>(age_col) == num_objects * 2 - 1);
        };

        BENCHMARK_ADVANCED("insert, delete odds")(Catch::Benchmark::Chronometer meter) {
            constexpr size_t num_objects = 200;
            r->begin_transaction();
            result.clear();
            r->commit_transaction();
            advance_and_notify(*r);

            // insert
            add_objects(num_objects);
            advance_and_notify(*r);

            // remove odds
            r->begin_transaction();
            for (size_t i = result.size(); i > 0; --i) {
                if (i % 2 == 1) {
                    Obj odd = result.get(i);
                    odd.remove();
                }
            }
            r->commit_transaction();

            num_insertions = 0;
            num_modifications = 0;
            num_deletions = 0;

            meter.measure([&r] {
                advance_and_notify(*r);
            });
            REQUIRE(num_insertions == 0);
            REQUIRE(num_modifications == 0);
            REQUIRE(num_deletions == num_objects / 2);
            REQUIRE(result.size() == num_objects / 2);
            REQUIRE(result.get(0).get<int64_t>(age_col) == 0);
            REQUIRE(result.get(1).get<int64_t>(age_col) == 2);
        };
    }
}
<|endoftext|>


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

// Stubs for Apache API
// don't care about memory leaks
// these are just stubs

#include <string>
#include <sstream>

#include <httpd.h>
#include <http_config.h>  // for the config functions
#include <http_request.h>
#include <http_protocol.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include <unixd.h>

#include <http_log.h>
#include "testBodies.hh"

#include <cstring>
#include <cassert>

unixd_config_rec unixd_config;

AP_DECLARE_NONSTD(int) ap_rprintf( request_rec *r, const char *fmt, ...)
{
    assert( r != NULL );
    assert( fmt != NULL );

    char* lDest = NULL;

    va_list l_ap;
    va_start(l_ap, fmt);

    int n = vasprintf( &lDest, fmt, l_ap);

    va_end(l_ap);

    if( r->filename == NULL ){
        r->filename = lDest;
    }
    else {
        std::string lNew(r->filename);
        lNew.append(lDest);
        free(r->filename);
        r->filename = strdup(lNew.c_str());
        free(lDest);
    }

     return n;
};

AP_DECLARE(int) ap_is_initial_req(request_rec *r)
{
    return 0;
};

const std::string getLevel(int level) {
    switch ( level ) {
    case APLOG_NOERRNO|APLOG_WARNING:
        return "warning";
    case APLOG_NOERRNO|APLOG_ERR:
        return "err";
    case APLOG_NOERRNO|APLOG_NOTICE:
        return "notice";
    case APLOG_NOERRNO|APLOG_INFO:
        return "info";
    case APLOG_NOERRNO|APLOG_DEBUG:
        return "debug";
    case APLOG_NOERRNO|APLOG_EMERG:
        return "crit";
    }
    return "unknown";
}

AP_DECLARE_NONSTD(void) ap_log_error(const char *file, int line, int level,
                             apr_status_t status, const server_rec *s,
                             const char *fmt, ...)
{

    char* lDest = NULL;
    va_list l_ap;
    va_start(l_ap, fmt);

    vasprintf( &lDest, fmt, l_ap);
    printf("%s: %s\n", getLevel(level).c_str(), lDest);

    va_end(l_ap);
}

AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
        {
    // NOP
        }

AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_request_config(apr_pool_t *p)
{
    void *conf_vector = apr_pcalloc(p, sizeof(void *) * 16);
     return reinterpret_cast<ap_conf_vector_t *>(conf_vector);

}

int bodyServed = 0;
#include <iostream>

AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *filter,
                                        apr_bucket_brigade *bb,
                                        ap_input_mode_t mode,
                                        apr_read_type_e block,
                                        apr_off_t readbytes)
{

    apr_pool_t *pool = NULL;
    apr_pool_create(&pool, 0);
    std::cout << "Filter " << filter << std::endl;
    // No filter, simply forge an EOS
    if (((void *)filter == (void *)0x42)) {

        assert(apr_brigade_write(bb, NULL, NULL, testBody42, std::string(testBody42).size()) == APR_SUCCESS);
    } else if ((void *)filter == (void *)0x43) {
        if (!bodyServed) {
            assert(apr_brigade_write(bb, NULL, NULL, testBody43p1,
                                     std::string(testBody43p1).size()) == APR_SUCCESS);
            bodyServed = 1;
            return APR_SUCCESS;
        } else if (bodyServed == 1) {
            assert(apr_brigade_write(bb, NULL, NULL,
                                     testBody43p2, std::string(testBody43p2).size()) == APR_SUCCESS);
            bodyServed = 2;
            return APR_SUCCESS;
        }
    } else if ((void *)filter == (void *)0x44) {
        return 1;
    }    apr_bucket_alloc_t *bA = apr_bucket_alloc_create(pool);
    apr_bucket *e = apr_bucket_eos_create(bA);
    assert(e);
    APR_BRIGADE_INSERT_TAIL(bb, e);
    return APR_SUCCESS;
}

AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
                                              request_rec *r, conn_rec *c)
{
	return NULL;
}

apr_status_t
ap_pass_brigade(ap_filter_t *, apr_bucket_brigade *)
{
    return APR_SUCCESS;
}

AP_DECLARE(void)
ap_remove_output_filter(ap_filter_t *pFilter)
{
}

AP_DECLARE(void)
ap_remove_input_filter(ap_filter_t *pFilter)
{
}

apr_status_t 	ap_filter_flush (apr_bucket_brigade *bb, void *ctx) {
    return APR_SUCCESS;
}
<commit_msg>Fixing stubs<commit_after>/*
* mod_dup - duplicates apache requests
*
* Copyright (C) 2013 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Stubs for Apache API
// don't care about memory leaks
// these are just stubs

#include <string>
#include <sstream>

#include <httpd.h>
#include <http_config.h>  // for the config functions
#include <http_request.h>
#include <http_protocol.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include <unixd.h>

#include <http_log.h>
#include "testBodies.hh"

#include <cstring>
#include <cassert>

unixd_config_rec unixd_config;

AP_DECLARE_NONSTD(int) ap_rprintf( request_rec *r, const char *fmt, ...)
{
    assert( r != NULL );
    assert( fmt != NULL );

    char* lDest = NULL;

    va_list l_ap;
    va_start(l_ap, fmt);

    int n = vasprintf( &lDest, fmt, l_ap);

    va_end(l_ap);

    if( r->filename == NULL ){
        r->filename = lDest;
    }
    else {
        std::string lNew(r->filename);
        lNew.append(lDest);
        free(r->filename);
        r->filename = strdup(lNew.c_str());
        free(lDest);
    }

     return n;
};

AP_DECLARE(int) ap_is_initial_req(request_rec *r)
{
    return 0;
};

const std::string getLevel(int level) {
    switch ( level ) {
    case APLOG_NOERRNO|APLOG_WARNING:
        return "warning";
    case APLOG_NOERRNO|APLOG_ERR:
        return "err";
    case APLOG_NOERRNO|APLOG_NOTICE:
        return "notice";
    case APLOG_NOERRNO|APLOG_INFO:
        return "info";
    case APLOG_NOERRNO|APLOG_DEBUG:
        return "debug";
    case APLOG_NOERRNO|APLOG_EMERG:
        return "crit";
    }
    return "unknown";
}

AP_DECLARE_NONSTD(void) ap_log_error(const char *file, int line, int level,
                             apr_status_t status, const server_rec *s,
                             const char *fmt, ...)
{

    char* lDest = NULL;
    va_list l_ap;
    va_start(l_ap, fmt);

    vasprintf( &lDest, fmt, l_ap);
    printf("%s: %s\n", getLevel(level).c_str(), lDest);

    va_end(l_ap);
}

AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
        {
    // NOP
        }

AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_request_config(apr_pool_t *p)
{
    void *conf_vector = apr_pcalloc(p, sizeof(void *) * 16);
     return reinterpret_cast<ap_conf_vector_t *>(conf_vector);

}

int bodyServed = 0;
#include <iostream>

AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *filter,
                                        apr_bucket_brigade *bb,
                                        ap_input_mode_t mode,
                                        apr_read_type_e block,
                                        apr_off_t readbytes)
{

    apr_pool_t *pool = NULL;
    apr_pool_create(&pool, 0);
    std::cout << "Filter " << filter << std::endl;
    // No filter, simply forge an EOS
    if (((void *)filter == (void *)0x42)) {

        assert(apr_brigade_write(bb, NULL, NULL, testBody42, std::string(testBody42).size()) == APR_SUCCESS);
    } else if ((void *)filter == (void *)0x43) {
        if (!bodyServed) {
            assert(apr_brigade_write(bb, NULL, NULL, testBody43p1,
                                     std::string(testBody43p1).size()) == APR_SUCCESS);
            bodyServed = 1;
            return APR_SUCCESS;
        } else if (bodyServed == 1) {
            assert(apr_brigade_write(bb, NULL, NULL,
                                     testBody43p2, std::string(testBody43p2).size()) == APR_SUCCESS);
            bodyServed = 2;
            return APR_SUCCESS;
        }
    } else if ((void *)filter == (void *)0x44) {
        return 1;
    }    apr_bucket_alloc_t *bA = apr_bucket_alloc_create(pool);
    apr_bucket *e = apr_bucket_eos_create(bA);
    assert(e);
    APR_BRIGADE_INSERT_TAIL(bb, e);
    return APR_SUCCESS;
}

AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
                                              request_rec *r, conn_rec *c)
{
	return NULL;
}

AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx,
                                              request_rec *r, conn_rec *c)
{
	return NULL;
}

apr_status_t
ap_pass_brigade(ap_filter_t *, apr_bucket_brigade *)
{
    return APR_SUCCESS;
}

AP_DECLARE(void)
ap_remove_output_filter(ap_filter_t *pFilter)
{
}

AP_DECLARE(void)
ap_remove_input_filter(ap_filter_t *pFilter)
{
}

apr_status_t 	ap_filter_flush (apr_bucket_brigade *bb, void *ctx) {
    return APR_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2016, Roland Bock
 * All rights reserved.
 *
 * 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.
 *
 * 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 <iostream>
#include <sqlpp11/remove.h>
#include "Sample.h"
#include "MockDb.h"
#include "is_regular.h"

int Remove(int, char* [])
{
  MockDb db = {};
  MockDb::_serializer_context_t printer = {};

  const auto t = test::TabBar{};
  const auto f = test::TabFoo{};

  {
    using T = decltype(remove_from(t));
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  {
    using T = decltype(remove_from(t).where(t.beta != "transparent"));
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  {
    using T = decltype(dynamic_remove_from(db, t).dynamic_using().dynamic_where());
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  serialize(remove_from(t), printer).str();
  serialize(remove_from(t).where(t.beta != "transparent"), printer).str();
  serialize(remove_from(t).using_(t), printer).str();
  serialize(remove_from(t).using_(f), printer).str();
  auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where();
  r.using_.add(t);
  r.where.add(t.beta != "transparent");
  printer.reset();
  std::cerr << serialize(r, printer).str() << std::endl;
  printer.reset();
  std::cerr << serialize(remove_from(t).unconditionally(), printer).str() << std::endl;

  db(r);

  return 0;
}
<commit_msg>Add example for #448<commit_after>/*
 * Copyright (c) 2013-2016, Roland Bock
 * All rights reserved.
 *
 * 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.
 *
 * 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 <iostream>
#include <sqlpp11/sqlpp11.h>
#include "Sample.h"
#include "MockDb.h"
#include "is_regular.h"

int Remove(int, char* [])
{
  MockDb db = {};
  MockDb::_serializer_context_t printer = {};

  const auto t = test::TabBar{};
  const auto f = test::TabFoo{};

  {
    using T = decltype(remove_from(t));
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  {
    using T = decltype(remove_from(t).where(t.beta != "transparent"));
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  {
    using T = decltype(dynamic_remove_from(db, t).dynamic_using().dynamic_where());
    static_assert(sqlpp::is_regular<T>::value, "type requirement");
  }

  serialize(remove_from(t), printer).str();
  serialize(remove_from(t).where(t.beta != "transparent"), printer).str();
  serialize(remove_from(t).using_(t), printer).str();
  serialize(remove_from(t).using_(f), printer).str();
  auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where();
  r.using_.add(t);
  r.where.add(t.beta != "transparent");
  printer.reset();
  std::cerr << serialize(r, printer).str() << std::endl;
  printer.reset();
  std::cerr << serialize(remove_from(t).unconditionally(), printer).str() << std::endl;

  db(r);

  remove_from(t).where(t.beta.in(select(f.delta).from(f).unconditionally()));

  return 0;
}
<|endoftext|>