<commit_before>#include "./thresholdScan.h"

ClassImp(thresholdScan);

//standard constructor from AnalysisModule
thresholdScan::thresholdScan(const char* name, const char* title,
                   const char* in_file_suffix, const char* out_file_suffix, const std::vector<double>& thresholds, const std::vector<double>& eCut)
                   : JPetCommonAnalysisModule(name, title, in_file_suffix, out_file_suffix)
{
  setVersion(MODULE_VERSION);
  fThresholds = thresholds;
  energyCuts = eCut;
}

//no specific destructor needed
thresholdScan::~thresholdScan()
{
}

void thresholdScan::begin()
{
	for( unsigned int i = 0; i < fThresholds.size(); i++ ){
		std::vector<double> k;
		fDeltaTimesForThresholdsTop.push_back( k );
		fDeltaTimesForThresholdsBottom.push_back( k );
	}
}

void thresholdScan::exec()
{

  // Take next entry
  fReader->getEntry(fEvent);

  // Cast data from the entry into JPetLOR
  const JPetLOR& lor = (JPetLOR&) fReader->getData();

  // Extract signals
  const JPetRecoSignal& signalFirst = lor.getFirstHit().getSignalA().getRecoSignal();
  const JPetRecoSignal& signalSecond = lor.getFirstHit().getSignalB().getRecoSignal();
  const JPetRecoSignal& signalThird = lor.getSecondHit().getSignalA().getRecoSignal();
  const JPetRecoSignal& signalFourth = lor.getSecondHit().getSignalB().getRecoSignal();

  const JPetHit& hitFirst = lor.getFirstHit();
  const JPetHit& hitSecond = lor.getSecondHit();
	double energyT = hitFirst.getEnergy();
	double energyB = hitSecond.getEnergy();

    if(energyCuts.size() == 2)
    {
	if( energyT > energyCuts[0] && energyT < energyCuts[1] )
	{
		energyTop.push_back(energyT);
	}

	if( energyB > energyCuts[0] && energyB < energyCuts[1] )
	{
		energyBottom.push_back(energyB);
	}
    }
    else if(energyCuts.size() == 1)
    {
        if( energyT > energyCuts[0] )
        {
                energyTop.push_back(energyT);
        }

        if( energyB > energyCuts[0] )
        {
                energyBottom.push_back(energyB);
        }
    }

  // Save times from signals to file
  for( unsigned int i = 0; i < fThresholds.size(); i++)
  {
    if(energyCuts.size() == 2)
    {
	if( energyT > energyCuts[0] && energyT < energyCuts[1] )
	{
		fDeltaTimesForThresholdsTop[i].push_back( signalFirst.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalSecond.getRecoTimeAtThreshold( (double)fThresholds[i] ) );
	}

	if(energyB > energyCuts[0] && energyB < energyCuts[1] )
	{
		fDeltaTimesForThresholdsBottom[i].push_back( signalThird.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalFourth.getRecoTimeAtThreshold( (double)fThresholds[i] ) );
	}
    }
    else if(energyCuts.size() == 1)
    {
      if(energyT > energyCuts[0] ){
                fDeltaTimesForThresholdsTop[i].push_back( signalFirst.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalSecond.getRecoTimeAtThreshold( (double)fThresholds[i] ) );
	}

      if(energyB > energyCuts[0] )
	{
                fDeltaTimesForThresholdsBottom[i].push_back( signalThird.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalFourth.getRecoTimeAtThreshold( (double)fThresholds[i] ) );
	}
    }
    else{
	ERROR( Form("Bad energy cuts vector provided") );
	}
 }
  fEvent++;
}

void thresholdScan::end()
{

	plotHistosAndGraphs( fDeltaTimesForThresholdsTop, "_TOP_");
	plotHistosAndGraphs( fDeltaTimesForThresholdsBottom, "_BOTTOM_");
	plotEnergyCuts(energyTop, "_TOP_");
	plotEnergyCuts(energyBottom, "_BOTTOM_");
}

void thresholdScan::plotEnergyCuts( std::vector<double>& data, std::string name)
{
  TString filePath = fHeader->getBaseFileName();
  filePath = filePath(filePath.Last('/')+1, filePath.Length()-1);
  filePath = filePath(0, filePath.Last('.'));

  std::stringstream buf;
  buf << fHeader->getSourcePosition();
  buf << "_";
  if( energyCuts.size() == 2 )
        buf << energyCuts[0] <<"-"<<energyCuts[1];
  else if (energyCuts.size() == 1 )
        buf << energyCuts[0] << "-inf";
  gStyle->SetOptFit(1);

  TString path = "ThresholdScan" + filePath+buf.str() + "/";
  TUnixSystem* system = new TUnixSystem();
  system->mkdir( (std::string(path)).c_str(), 1);

          std::string title = buf.str();
          title+=name;

          TH1F* energy = new TH1F( title.c_str(), title.c_str() , 250, 0, 500);

          for(unsigned int i = 0; i < data.size(); i++){
                       energy->Fill( data[i] );
          }
        TCanvas* c1 = new TCanvas();
        energy->Draw();
        c1->SaveAs( ((std::string)path+title+".png").c_str() );

        delete energy;
}

void thresholdScan::plotHistosAndGraphs( std::vector<std::vector<double> >& data, std::string name)
{
  std::vector<double> resolutions;
  std::vector<double> chi2;

  TString filePath = fHeader->getBaseFileName();
  filePath = filePath(filePath.Last('/')+1, filePath.Length()-1);
  filePath = filePath(0, filePath.Last('.'));

  std::stringstream buf;
  buf << fHeader->getSourcePosition();
  	if( energyCuts.size() == 2 )
		buf <<"_"<< energyCuts[0] <<"-"<<energyCuts[1];
	else if (energyCuts.size() == 1 )
		buf << "_" <<energyCuts[0] << "-inf";
  gStyle->SetOptFit(1);

  TString path = "ThresholdScan" + filePath+buf.str() + "/";
  TUnixSystem* system = new TUnixSystem();
  system->mkdir( (std::string(path)).c_str(), 1);

  for(unsigned int j = 0; j < fThresholds.size(); j++){
          double thr = fThresholds[j];
          std::stringstream buf; buf << thr;
          std::string title = buf.str();
          title+="mV";
	  title+=name;

          TH1F* deltaT = new TH1F( title.c_str(), title.c_str() , 200, -5000, 5000);

          for(unsigned int i = 0; i < data[j].size(); i++){
		if( 0 == data[j].size())
		  break;
                if( data[j][i] != 0 )
                        deltaT->Fill( data[j][i] );
          }

        TCanvas* c1 = new TCanvas();
	  deltaT->Sumw2();
	double eventsNotInRange = deltaT->GetBinContent(0) + deltaT->GetBinContent(201);
	if( eventsNotInRange != deltaT->GetEntries() )
	{
		std::cout<< deltaT->GetEntries() << std::endl;
	        deltaT->Fit("gaus","QI");
       		resolutions.push_back( (double)deltaT->GetFunction("gaus")->GetParameter(2) );
		chi2.push_back( ( (double)deltaT->GetFunction("gaus")->GetChisquare() ) / ( (double)deltaT->GetFunction("gaus")->GetNDF() ) );
	}
	else
	{
		resolutions.push_back(0);
		chi2.push_back(0);
	}
        deltaT->Draw();
	title+=buf.str();
        c1->SaveAs( ((std::string)path+title+".png").c_str() );

        delete deltaT;
  }

  std::ofstream outFile;

  outFile.open( ((std::string)path+name + "resolutions"+buf.str()+".txt").c_str() );

  for(unsigned int i = 0; i < resolutions.size(); i++){
        outFile << fThresholds[i] << "\t"<< resolutions[i] << "\t" << chi2[i] <<  std::endl;
  }

  outFile.close();

  TCanvas* c1 = new TCanvas();
  TGraph* resGraph = new TGraph(resolutions.size(),&fThresholds[0], &resolutions[0]);
  resGraph->SetTitle( "" );
  resGraph->SetMarkerStyle(21);
  resGraph->SetMarkerSize(1.4);
  resGraph->GetXaxis()->SetTitle("Threshold [mV]");
  resGraph->GetYaxis()->SetTitle("Time difference resolution [ps]");
  resGraph->GetXaxis()->SetLabelFont(42);
  resGraph->GetYaxis()->SetLabelFont(42);
  resGraph->GetXaxis()->SetLabelSize(0.06);
  resGraph->GetYaxis()->SetLabelSize(0.06);
  resGraph->GetYaxis()->SetTitleOffset(1.2);
  resGraph->GetXaxis()->SetTitleFont(42);
  resGraph->GetYaxis()->SetTitleFont(42);
  resGraph->GetXaxis()->SetTitleSize(0.06);
  resGraph->GetYaxis()->SetTitleSize(0.06);

  c1->SetLeftMargin(0.1716621);
  c1->SetRightMargin(0.02815622);
  c1->SetTopMargin(0.02572016);
  c1->SetBottomMargin(0.1738683);

  resGraph->Draw("AP");
  c1->SaveAs( ((std::string)path+name+buf.str()+"graph.root").c_str() );
  resGraph->Draw("AP");
  c1->SaveAs( ((std::string)path+name+"graph.png").c_str() );

  delete resGraph;

}

<commit_msg>Clean commented code<commit_after>#include "./thresholdScan.h"

ClassImp(thresholdScan);

//standard constructor from AnalysisModule
thresholdScan::thresholdScan(const char* name, const char* title,
                   const char* in_file_suffix, const char* out_file_suffix, const std::vector<double>& thresholds, const std::vector<double>& eCut)
                   : JPetCommonAnalysisModule(name, title, in_file_suffix, out_file_suffix)
{
  setVersion(MODULE_VERSION);
  fThresholds = thresholds;
  energyCuts = eCut;
}

//no specific destructor needed
thresholdScan::~thresholdScan()
{
}

void thresholdScan::begin()
{
	for( unsigned int i = 0; i < fThresholds.size(); i++ ){
		std::vector<double> k;
		fDeltaTimesForThresholdsTop.push_back( k );
		fDeltaTimesForThresholdsBottom.push_back( k );
	}
}

void thresholdScan::exec()
{

  // Take next entry
  fReader->getEntry(fEvent);

  // Cast data from the entry into JPetLOR
  const JPetLOR& lor = (JPetLOR&) fReader->getData();

   std::cout << "Doing optimisation for: " << lor.getFirstHit().getSignalA().getPM().getID() << " and "
   << lor.getFirstHit().getSignalB().getPM().getID() << std::endl;

  // Extract signals
  const JPetRecoSignal& signalFirst = lor.getFirstHit().getSignalA().getRecoSignal();
  const JPetRecoSignal& signalSecond = lor.getFirstHit().getSignalB().getRecoSignal();
  const JPetRecoSignal& signalThird = lor.getSecondHit().getSignalA().getRecoSignal();
  const JPetRecoSignal& signalFourth = lor.getSecondHit().getSignalB().getRecoSignal();

  const JPetHit& hitFirst = lor.getFirstHit();
  const JPetHit& hitSecond = lor.getSecondHit();
	double energyT = hitFirst.getEnergy();
	double energyB = hitSecond.getEnergy();
	double chargeOne = signalFirst.getCharge();
	double chargeTwo = signalSecond.getCharge();
	double ampOne = signalFirst.getAmplitude();
	double ampTwo = signalSecond.getAmplitude();

  // Save times from signals to file
  for( unsigned int i = 0; i < fThresholds.size(); i++)
  {
//     if(energyCuts.size() == 2)
//     {
// 	if( chargeOne > 352 && chargeTwo > 395 )
//  	if( ampOne > 350 && ampTwo > 350 )
//  	{
		fDeltaTimesForThresholdsTop[i].push_back( signalFirst.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalThird.getRecoTimeAtThreshold( (double)fThresholds[i] ) );
//  	}

		fDeltaTimesForThresholdsBottom[i].push_back( signalFirst.getRecoTimeAtThreshold( (double)fThresholds[i] ) - signalSecond.getRecoTimeAtThreshold( (double)fThresholds[i] ) );

 }
  fEvent++;
}

void thresholdScan::end()
{

	plotHistosAndGraphs( fDeltaTimesForThresholdsTop, "_TOP_");
	plotHistosAndGraphs( fDeltaTimesForThresholdsBottom, "_BOTTOM_");
	plotEnergyCuts(energyTop, "_TOP_");
	plotEnergyCuts(energyBottom, "_BOTTOM_");
}

void thresholdScan::plotEnergyCuts( std::vector<double>& data, std::string name)
{
  TString filePath = fHeader->getBaseFileName();
  filePath = filePath(filePath.Last('/')+1, filePath.Length()-1);
  filePath = filePath(0, filePath.Last('.'));

  std::stringstream buf;
  buf << fHeader->getSourcePosition();
  buf << "_";
  if( energyCuts.size() == 2 )
        buf << energyCuts[0] <<"-"<<energyCuts[1];
  else if (energyCuts.size() == 1 )
        buf << energyCuts[0] << "-inf";
  gStyle->SetOptFit(1);

  TString path = "ThresholdScan" + filePath+buf.str() + "/";
  TUnixSystem* system = new TUnixSystem();
  system->mkdir( (std::string(path)).c_str(), 1);

          std::string title = buf.str();
          title+=name;

          TH1F* energy = new TH1F( title.c_str(), title.c_str() , 250, 0, 500);

          for(unsigned int i = 0; i < data.size(); i++){
                       energy->Fill( data[i] );
          }
        TCanvas* c1 = new TCanvas();
        energy->Draw();
        c1->SaveAs( ((std::string)path+title+".png").c_str() );

        delete energy;
}

void thresholdScan::plotHistosAndGraphs( std::vector<std::vector<double> >& data, std::string name)
{
  std::vector<double> resolutions;
  std::vector<double> chi2;

  TString filePath = fHeader->getBaseFileName();
  filePath = filePath(filePath.Last('/')+1, filePath.Length()-1);
  filePath = filePath(0, filePath.Last('.'));

  std::stringstream buf;
  buf << fHeader->getSourcePosition();
  	if( energyCuts.size() == 2 )
		buf <<"_"<< energyCuts[0] <<"-"<<energyCuts[1];
	else if (energyCuts.size() == 1 )
		buf << "_" <<energyCuts[0] << "-inf";
  gStyle->SetOptFit(1);

  TString path = "ThresholdScan" + filePath+buf.str() + "/";
  TUnixSystem* system = new TUnixSystem();
  system->mkdir( (std::string(path)).c_str(), 1);

  for(unsigned int j = 0; j < fThresholds.size(); j++){
          double thr = fThresholds[j];
          std::stringstream buf; buf << thr;
          std::string title = buf.str();
          title+="mV";
	  title+=name;

          TH1F* deltaT = new TH1F( title.c_str(), title.c_str() , 400, -10000, 10000);

          for(unsigned int i = 0; i < data[j].size(); i++){
		if( 0 == data[j].size())
		  break;
                if( data[j][i] != 0 )
                        deltaT->Fill( data[j][i] );
          }

        TCanvas* c1 = new TCanvas();
	  deltaT->Sumw2();
	double eventsNotInRange = deltaT->GetBinContent(0) + deltaT->GetBinContent(201);
	if( eventsNotInRange != deltaT->GetEntries() )
	{
		std::cout<< deltaT->GetEntries() << std::endl;
	        deltaT->Fit("gaus","QI");
       		resolutions.push_back( (double)deltaT->GetFunction("gaus")->GetParameter(2) );
		chi2.push_back( ( (double)deltaT->GetFunction("gaus")->GetChisquare() ) / ( (double)deltaT->GetFunction("gaus")->GetNDF() ) );
	}
	else
	{
		resolutions.push_back(0);
		chi2.push_back(0);
	}
        deltaT->Draw();
	title+=buf.str();
        c1->SaveAs( ((std::string)path+title+".png").c_str() );

        delete deltaT;
  }

  std::ofstream outFile;

  outFile.open( ((std::string)path+name + "resolutions"+buf.str()+".txt").c_str() );

  for(unsigned int i = 0; i < resolutions.size(); i++){
        outFile << fThresholds[i] << "\t"<< resolutions[i] << "\t" << chi2[i] <<  std::endl;
  }

  outFile.close();

  TCanvas* c1 = new TCanvas();
  TGraph* resGraph = new TGraph(resolutions.size(),&fThresholds[0], &resolutions[0]);
  resGraph->SetTitle( "" );
  resGraph->SetMarkerStyle(21);
  resGraph->SetMarkerSize(1.4);
  resGraph->GetXaxis()->SetTitle("Threshold [mV]");
  resGraph->GetYaxis()->SetTitle("Time difference resolution [ps]");
  resGraph->GetXaxis()->SetLabelFont(42);
  resGraph->GetYaxis()->SetLabelFont(42);
  resGraph->GetXaxis()->SetLabelSize(0.06);
  resGraph->GetYaxis()->SetLabelSize(0.06);
  resGraph->GetYaxis()->SetTitleOffset(1.2);
  resGraph->GetXaxis()->SetTitleFont(42);
  resGraph->GetYaxis()->SetTitleFont(42);
  resGraph->GetXaxis()->SetTitleSize(0.06);
  resGraph->GetYaxis()->SetTitleSize(0.06);

  c1->SetLeftMargin(0.1716621);
  c1->SetRightMargin(0.02815622);
  c1->SetTopMargin(0.02572016);
  c1->SetBottomMargin(0.1738683);

  resGraph->Draw("AP");
  c1->SaveAs( ((std::string)path+name+buf.str()+"graph.root").c_str() );
  resGraph->Draw("AP");
  c1->SaveAs( ((std::string)path+name+"graph.png").c_str() );

  delete resGraph;

}

<|endoftext|>


<commit_before><commit_msg>All overflow scrolls should clear the scroll anchor, not just the root layer.<commit_after><|endoftext|>


<commit_before>#include "physics/kepler_orbit.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mathematica/mathematica.hpp"
#include "physics/solar_system.hpp"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using integrators::McLachlanAtela1992Order5Optimal;
using quantities::si::Degree;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;

namespace physics {

class ResonanceTest : public ::testing::Test {
 protected:
  using KSP =
      Frame<serialization::Frame::TestTag, serialization::Frame::TEST, true>;

  // Gravitational parameters from the KSP wiki.
  ResonanceTest()
      : sun_(AddBody(1.1723328E+18 * Pow<3>(Metre) / Pow<2>(Second))),
        jool_(AddBody(2.8252800E+14 * Pow<3>(Metre) / Pow<2>(Second))),
        laythe_(AddBody(1.9620000E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        vall_(AddBody(2.0748150E+11 * Pow<3>(Metre) / Pow<2>(Second))),
        tylo_(AddBody(2.8252800E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        bop_(AddBody(2.4868349E+09 * Pow<3>(Metre) / Pow<2>(Second))),
        pol_(AddBody(7.2170208E+08 * Pow<3>(Metre) / Pow<2>(Second))) {
    // Elements from the KSP wiki.
    jool_elements_.eccentricity = 0.05;
    jool_elements_.semimajor_axis = 68'773'560'320 * Metre;
    jool_elements_.inclination = 1.304 * Degree;
    jool_elements_.longitude_of_ascending_node = 52 * Degree;
    jool_elements_.argument_of_periapsis =  0 * Degree;
    jool_elements_.mean_anomaly = 0.1 * Radian;
    laythe_elements_.eccentricity = 0;
    laythe_elements_.semimajor_axis = 27'184'000 * Metre;
    laythe_elements_.inclination = 0 * Degree;
    laythe_elements_.longitude_of_ascending_node = 0 * Degree;
    laythe_elements_.argument_of_periapsis = 0 * Degree;
    laythe_elements_.mean_anomaly = 3.14 * Radian;
    vall_elements_.eccentricity = 0;
    vall_elements_.semimajor_axis = 43'152'000 * Metre;
    vall_elements_.inclination = 0 * Degree;
    vall_elements_.longitude_of_ascending_node = 0 * Degree;
    vall_elements_.argument_of_periapsis = 0 * Degree;
    vall_elements_.mean_anomaly = 0.9 * Radian;
    tylo_elements_.eccentricity = 0;
    tylo_elements_.semimajor_axis = 68'500'000 * Metre;
    tylo_elements_.inclination = 0.025 * Degree;
    tylo_elements_.longitude_of_ascending_node = 0 * Degree;
    tylo_elements_.argument_of_periapsis = 0 * Degree;
    tylo_elements_.mean_anomaly = 3.14 * Radian;
    bop_elements_.eccentricity = 0.24;
    bop_elements_.semimajor_axis = 128'500'000 * Metre;
    bop_elements_.inclination = 15 * Degree;
    bop_elements_.longitude_of_ascending_node = 10 * Degree;
    bop_elements_.argument_of_periapsis = 25 * Degree;
    bop_elements_.mean_anomaly = 0.9 * Radian;
    pol_elements_.eccentricity = 0.17;
    pol_elements_.semimajor_axis = 179'890'000 * Metre;
    pol_elements_.inclination = 4.25 * Degree;
    pol_elements_.longitude_of_ascending_node = 2 * Degree;
    pol_elements_.argument_of_periapsis = 15 * Degree;
    pol_elements_.mean_anomaly = 0.9 * Radian;
  }

  std::vector<not_null<std::unique_ptr<MassiveBody const>>> bodies_;
  not_null<MassiveBody const *> const sun_, jool_, laythe_, vall_, tylo_, bop_,
      pol_;
  MasslessBody test_particle_;
  Instant const game_epoch_;
  DegreesOfFreedom<KSP> const origin_ = {KSP::origin, Velocity<KSP>()};
  KeplerianElements<KSP> jool_elements_, laythe_elements_, vall_elements_,
      tylo_elements_, bop_elements_, pol_elements_;

 private:
  not_null<MassiveBody const*> AddBody(GravitationalParameter const& μ) {
    bodies_.emplace_back(make_not_null_unique<MassiveBody>(μ));
    return bodies_.back().get();
  }
};

TEST_F(ResonanceTest, JoolSystem) {
  auto const stock_jool_orbit =
      KeplerOrbit<KSP>(*sun_, test_particle_, game_epoch_, jool_elements_);
  auto const stock_laythe_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, laythe_elements_);
  auto const stock_vall_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, vall_elements_);
  auto const stock_tylo_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, tylo_elements_);
  auto const stock_bop_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, bop_elements_);
  auto const stock_pol_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, pol_elements_);

  auto const stock_jool_initial_state =
      origin_ + stock_jool_orbit.PrimocentricStateVectors(game_epoch_);
  Ephemeris<KSP> stock_ephemeris(
      std::move(bodies_),
      {origin_,
       stock_jool_initial_state,
       stock_jool_initial_state +
           stock_laythe_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_vall_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_tylo_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_bop_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_pol_orbit.PrimocentricStateVectors(game_epoch_)},
      game_epoch_,
      McLachlanAtela1992Order5Optimal<Position<KSP>>(),
      45 * Minute,
      5 * Milli(Metre));
  stock_ephemeris.Prolong(game_epoch_ + 90 * Day);
  std::vector<Instant> times;
  std::vector<std::vector<Displacement<KSP>>> displacements;
  for (Instant t = game_epoch_; t < game_epoch_ + 90 * Day; t += 45 * Minute) {
    auto const position = [&stock_ephemeris, t](
        not_null<MassiveBody const*> body) {
      return stock_ephemeris.trajectory(body)->EvaluatePosition(t, nullptr);
    };
    auto const barycentre = Barycentre<Position<KSP>, Mass>(
        {position(jool_), position(laythe_), position(vall_), position(tylo_),
         position(bop_), position(pol_)},
        {jool_->mass(), laythe_->mass(), vall_->mass(), tylo_->mass(),
         bop_->mass(), pol_->mass()});
    times.emplace_back(t);
    displacements.push_back(
        {position(jool_) - barycentre, position(laythe_) - barycentre,
         position(vall_) - barycentre, position(tylo_) - barycentre,
         position(bop_) - barycentre, position(pol_) - barycentre});
  }
  std::ofstream file;
  file.open("stock_jool.wl");
  file << mathematica::Assign("q", displacements);
  file << mathematica::Assign("t", times);
  file.close();
  // fails.
  stock_ephemeris.Prolong(game_epoch_ + 100 * Day);
}

}  // namespace physics
}  // namespace principia
<commit_msg>first correction that's not strictly worse than stock...<commit_after>#include "physics/kepler_orbit.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mathematica/mathematica.hpp"
#include "physics/solar_system.hpp"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using integrators::McLachlanAtela1992Order5Optimal;
using quantities::si::Degree;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;

namespace physics {

class ResonanceTest : public ::testing::Test {
 protected:
  using KSP =
      Frame<serialization::Frame::TestTag, serialization::Frame::TEST, true>;

  // Gravitational parameters from the KSP wiki.
  ResonanceTest()
      : sun_(AddBody(1.1723328E+18 * Pow<3>(Metre) / Pow<2>(Second))),
        jool_(AddBody(2.8252800E+14 * Pow<3>(Metre) / Pow<2>(Second))),
        laythe_(AddBody(1.9620000E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        vall_(AddBody(2.0748150E+11 * Pow<3>(Metre) / Pow<2>(Second))),
        tylo_(AddBody(2.8252800E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        bop_(AddBody(2.4868349E+09 * Pow<3>(Metre) / Pow<2>(Second))),
        pol_(AddBody(7.2170208E+08 * Pow<3>(Metre) / Pow<2>(Second))) {
    // Elements from the KSP wiki.
    jool_elements_.eccentricity = 0.05;
    jool_elements_.semimajor_axis = 68'773'560'320 * Metre;
    jool_elements_.inclination = 1.304 * Degree;
    jool_elements_.longitude_of_ascending_node = 52 * Degree;
    jool_elements_.argument_of_periapsis =  0 * Degree;
    jool_elements_.mean_anomaly = 0.1 * Radian;
    laythe_elements_.eccentricity = 0;
    laythe_elements_.semimajor_axis = 27'184'000 * Metre;
    laythe_elements_.inclination = 0 * Degree;
    laythe_elements_.longitude_of_ascending_node = 0 * Degree;
    laythe_elements_.argument_of_periapsis = 0 * Degree;
    laythe_elements_.mean_anomaly = 3.14 * Radian;
    vall_elements_.eccentricity = 0;
    vall_elements_.semimajor_axis = 43'152'000 * Metre;
    vall_elements_.inclination = 0 * Degree;
    vall_elements_.longitude_of_ascending_node = 0 * Degree;
    vall_elements_.argument_of_periapsis = 0 * Degree;
    vall_elements_.mean_anomaly = 0.9 * Radian;
    tylo_elements_.eccentricity = 0;
    tylo_elements_.semimajor_axis = 68'500'000 * Metre;
    tylo_elements_.inclination = 0.025 * Degree;
    tylo_elements_.longitude_of_ascending_node = 0 * Degree;
    tylo_elements_.argument_of_periapsis = 0 * Degree;
    tylo_elements_.mean_anomaly = 3.14 * Radian;
    bop_elements_.eccentricity = 0.24;
    bop_elements_.semimajor_axis = 128'500'000 * Metre;
    bop_elements_.inclination = 15 * Degree;
    bop_elements_.longitude_of_ascending_node = 10 * Degree;
    bop_elements_.argument_of_periapsis = 25 * Degree;
    bop_elements_.mean_anomaly = 0.9 * Radian;
    pol_elements_.eccentricity = 0.17;
    pol_elements_.semimajor_axis = 179'890'000 * Metre;
    pol_elements_.inclination = 4.25 * Degree;
    pol_elements_.longitude_of_ascending_node = 2 * Degree;
    pol_elements_.argument_of_periapsis = 15 * Degree;
    pol_elements_.mean_anomaly = 0.9 * Radian;
  }

  std::vector<not_null<std::unique_ptr<MassiveBody const>>> bodies_;
  not_null<MassiveBody const *> const sun_, jool_, laythe_, vall_, tylo_, bop_,
      pol_;
  MasslessBody test_particle_;
  Instant const game_epoch_;
  DegreesOfFreedom<KSP> const origin_ = {KSP::origin, Velocity<KSP>()};
  KeplerianElements<KSP> jool_elements_, laythe_elements_, vall_elements_,
      tylo_elements_, bop_elements_, pol_elements_;

 private:
  not_null<MassiveBody const*> AddBody(GravitationalParameter const& μ) {
    bodies_.emplace_back(make_not_null_unique<MassiveBody>(μ));
    return bodies_.back().get();
  }
};

TEST_F(ResonanceTest, StockJoolSystem) {
  auto const jool_orbit =
      KeplerOrbit<KSP>(*sun_, test_particle_, game_epoch_, jool_elements_);
  auto const laythe_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, laythe_elements_);
  auto const vall_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, vall_elements_);
  auto const tylo_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, tylo_elements_);
  auto const bop_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, bop_elements_);
  auto const pol_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, pol_elements_);

  auto const jool_initial_state =
      origin_ + jool_orbit.PrimocentricStateVectors(game_epoch_);
  Ephemeris<KSP> ephemeris(
      std::move(bodies_),
      {origin_,
       jool_initial_state,
       jool_initial_state + laythe_orbit.PrimocentricStateVectors(game_epoch_),
       jool_initial_state + vall_orbit.PrimocentricStateVectors(game_epoch_),
       jool_initial_state + tylo_orbit.PrimocentricStateVectors(game_epoch_),
       jool_initial_state + bop_orbit.PrimocentricStateVectors(game_epoch_),
       jool_initial_state + pol_orbit.PrimocentricStateVectors(game_epoch_)},
      game_epoch_,
      McLachlanAtela1992Order5Optimal<Position<KSP>>(),
      45 * Minute,
      5 * Milli(Metre));
  ephemeris.Prolong(game_epoch_ + 90 * Day);
  std::vector<Instant> times;
  std::vector<std::vector<Displacement<KSP>>> displacements;
  for (Instant t = game_epoch_; t < game_epoch_ + 90 * Day; t += 45 * Minute) {
    auto const position = [&ephemeris, t](
        not_null<MassiveBody const*> body) {
      return ephemeris.trajectory(body)->EvaluatePosition(t, nullptr);
    };
    auto const barycentre = Barycentre<Position<KSP>, Mass>(
        {position(jool_), position(laythe_), position(vall_), position(tylo_),
         position(bop_), position(pol_)},
        {jool_->mass(), laythe_->mass(), vall_->mass(), tylo_->mass(),
         bop_->mass(), pol_->mass()});
    times.emplace_back(t);
    displacements.push_back(
        {position(jool_) - barycentre, position(laythe_) - barycentre,
         position(vall_) - barycentre, position(tylo_) - barycentre,
         position(bop_) - barycentre, position(pol_) - barycentre});
  }
  std::ofstream file;
  file.open("stock_jool.wl");
  file << mathematica::Assign("q", displacements);
  file << mathematica::Assign("t", times);
  file.close();
  // fails.
  ephemeris.Prolong(game_epoch_ + 100 * Day);
}

TEST_F(ResonanceTest, BarycentricJoolSystem) {
  auto const jool_orbit =
      KeplerOrbit<KSP>(*sun_, *jool_, game_epoch_, jool_elements_);
  auto const laythe_orbit =
      KeplerOrbit<KSP>(*jool_, *laythe_, game_epoch_, laythe_elements_);
  MassiveBody jool_1(jool_->gravitational_parameter() +
                     laythe_->gravitational_parameter());
  auto const vall_orbit =
      KeplerOrbit<KSP>(jool_1, *vall_, game_epoch_, vall_elements_);
  MassiveBody jool_2(jool_1.gravitational_parameter() +
                     vall_->gravitational_parameter());
  auto const tylo_orbit =
      KeplerOrbit<KSP>(jool_2, *tylo_, game_epoch_, tylo_elements_);
  MassiveBody jool_3(jool_2.gravitational_parameter() +
                     tylo_->gravitational_parameter());
  auto const bop_orbit =
      KeplerOrbit<KSP>(jool_3, *bop_, game_epoch_, bop_elements_);
  MassiveBody jool_4(jool_3.gravitational_parameter() +
                     bop_->gravitational_parameter());
  auto const pol_orbit =
      KeplerOrbit<KSP>(jool_4, *pol_, game_epoch_, pol_elements_);

  auto const jool_barycentre_initial_state =
      origin_ + jool_orbit.BarycentricStateVectors(game_epoch_);
  auto const laythe_from_barycentre =
      laythe_orbit.BarycentricStateVectors(game_epoch_);
  auto const vall_from_barycentre =
      vall_orbit.BarycentricStateVectors(game_epoch_);
  auto const tylo_from_barycentre =
      tylo_orbit.BarycentricStateVectors(game_epoch_);
  auto const bop_from_barycentre =
      bop_orbit.BarycentricStateVectors(game_epoch_);
  auto const pol_from_barycentre =
      pol_orbit.BarycentricStateVectors(game_epoch_);
  auto const jool_initial_state = jool_barycentre_initial_state -
                                  (laythe_from_barycentre * laythe_->mass() +
                                   vall_from_barycentre * vall_->mass() +
                                   tylo_from_barycentre * tylo_->mass() +
                                   bop_from_barycentre * bop_->mass() +
                                   pol_from_barycentre * pol_->mass()) /
                                      jool_->mass();
  Ephemeris<KSP> ephemeris(
      std::move(bodies_),
      {origin_,  // TODO: not actually here
       jool_initial_state,
       jool_barycentre_initial_state + laythe_from_barycentre,
       jool_barycentre_initial_state + vall_from_barycentre,
       jool_barycentre_initial_state + tylo_from_barycentre,
       jool_barycentre_initial_state + bop_from_barycentre,
       jool_barycentre_initial_state + pol_from_barycentre},
      game_epoch_,
      McLachlanAtela1992Order5Optimal<Position<KSP>>(),
      45 * Minute,
      5 * Milli(Metre));
  ephemeris.Prolong(game_epoch_ + 90 * Day);
  std::vector<Instant> times;
  std::vector<std::vector<Displacement<KSP>>> displacements;
  for (Instant t = game_epoch_; t < game_epoch_ + 90 * Day; t += 45 * Minute) {
    auto const position = [&ephemeris, t](
        not_null<MassiveBody const*> body) {
      return ephemeris.trajectory(body)->EvaluatePosition(t, nullptr);
    };
    auto const barycentre = Barycentre<Position<KSP>, Mass>(
        {position(jool_), position(laythe_), position(vall_), position(tylo_),
         position(bop_), position(pol_)},
        {jool_->mass(), laythe_->mass(), vall_->mass(), tylo_->mass(),
         bop_->mass(), pol_->mass()});
    times.emplace_back(t);
    displacements.push_back(
        {position(jool_) - barycentre, position(laythe_) - barycentre,
         position(vall_) - barycentre, position(tylo_) - barycentre,
         position(bop_) - barycentre, position(pol_) - barycentre});
  }
  std::ofstream file;
  file.open("corrected_jool.wl");
  file << mathematica::Assign("q", displacements);
  file << mathematica::Assign("t", times);
  file.close();
  // fails.
  ephemeris.Prolong(game_epoch_ + 100 * Day);
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * 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.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "config.h"

#include "xterm_mouse.hh"

const char *xterm_mouse::XT_TERMCAP          = "\033[?1000%?%p1%{1}%=%th%el%;";
const char *xterm_mouse::XT_TERMCAP_TRACKING = "\033[?1002%?%p1%{1}%=%th%el%;";
const char *xterm_mouse::XT_TERMCAP_SGR      = "\033[?1006%?%p1%{1}%=%th%el%;";

void xterm_mouse::handle_mouse()
{
    bool release = false;
    int ch;
    size_t index = 0;
    int bstate, x, y;
    char buffer[64];
    bool done = false;

    while (!done) {
        if (index >= sizeof(buffer) - 1) {
            break;
        }
        ch = getch();
        switch (ch) {
            case 'm':
                release = true;
                done = true;
                break;
            case 'M':
                done = true;
                break;
            default:
                buffer[index++] = (char)ch;
                break;
        }
    }
    buffer[index] = '\0';

    if (sscanf(buffer, "<%d;%d;%d", &bstate, &x, &y) == 3) {
        if (this->xm_behavior) {
            this->xm_behavior->mouse_event(bstate, release, x, y);
        }
    }
    else {
        log_error("bad mouse escape sequence: %s", buffer);
    }
}

void xterm_mouse::set_enabled(bool enabled)
{
    if (is_available()) {
        putp(tparm((char *)XT_TERMCAP, enabled ? 1 : 0));
        putp(tparm((char *)XT_TERMCAP_TRACKING, enabled ? 1 : 0));
        putp(tparm((char *)XT_TERMCAP_SGR, enabled ? 1 : 0));
        fflush(stdout);
        this->xm_enabled = enabled;
    } else {
        log_warning("mouse support is not available");
    }
}

bool xterm_mouse::is_available()
{
    const char *termname = getenv("TERM");
    bool retval = false;

    if (termname and strstr(termname, "xterm") != NULL) {
        retval = isatty(STDOUT_FILENO);
    }
    return retval;
}
<commit_msg>[mouse] do not require xterm for mouse use<commit_after>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * 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.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "config.h"

#include "xterm_mouse.hh"

const char *xterm_mouse::XT_TERMCAP          = "\033[?1000%?%p1%{1}%=%th%el%;";
const char *xterm_mouse::XT_TERMCAP_TRACKING = "\033[?1002%?%p1%{1}%=%th%el%;";
const char *xterm_mouse::XT_TERMCAP_SGR      = "\033[?1006%?%p1%{1}%=%th%el%;";

void xterm_mouse::handle_mouse()
{
    bool release = false;
    int ch;
    size_t index = 0;
    int bstate, x, y;
    char buffer[64];
    bool done = false;

    while (!done) {
        if (index >= sizeof(buffer) - 1) {
            break;
        }
        ch = getch();
        switch (ch) {
            case 'm':
                release = true;
                done = true;
                break;
            case 'M':
                done = true;
                break;
            default:
                buffer[index++] = (char)ch;
                break;
        }
    }
    buffer[index] = '\0';

    if (sscanf(buffer, "<%d;%d;%d", &bstate, &x, &y) == 3) {
        if (this->xm_behavior) {
            this->xm_behavior->mouse_event(bstate, release, x, y);
        }
    }
    else {
        log_error("bad mouse escape sequence: %s", buffer);
    }
}

void xterm_mouse::set_enabled(bool enabled)
{
    if (is_available()) {
        putp(tparm((char *)XT_TERMCAP, enabled ? 1 : 0));
        putp(tparm((char *)XT_TERMCAP_TRACKING, enabled ? 1 : 0));
        putp(tparm((char *)XT_TERMCAP_SGR, enabled ? 1 : 0));
        fflush(stdout);
        this->xm_enabled = enabled;
    } else {
        log_warning("mouse support is not available");
    }
}

bool xterm_mouse::is_available()
{
    return isatty(STDOUT_FILENO);
}
<|endoftext|>


<commit_before>#include "_app/sdl.h"
#include "SDL/SDL.h"

st::_app::sdl::sdl() {
    init();
}

st::_app::sdl::~sdl() {
    finish();
}

bool st::_app::sdl::init() {
    SDL_Init ( SDL_INIT_EVERYTHING );
    SDL_Surface* hello;
    m_screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE );
    // Let's be honest, right now I don't care. # COPIED!!!
    hello = SDL_LoadBMP(media()->get_image_media_path("hello.bmp").c_str());
    SDL_BlitSurface(hello, NULL, m_screen, NULL);
    SDL_Flip( m_screen );
    SDL_Delay( 2000 );
    return true;
}

bool st::_app::sdl::finish() {
    SDL_Quit();
    // Let's be honest, right now I don't care.
    return true;
}
<commit_msg>Free missed screen.<commit_after>#include "_app/sdl.h"
#include "SDL/SDL.h"

st::_app::sdl::sdl() {
    init();
}

st::_app::sdl::~sdl() {
    finish();
}

bool st::_app::sdl::init() {
    SDL_Init ( SDL_INIT_EVERYTHING );
    SDL_Surface* hello;
    m_screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE );
    // Let's be honest, right now I don't care. # COPIED!!!
    hello = SDL_LoadBMP(media()->get_image_media_path("hello.bmp").c_str());
    SDL_BlitSurface(hello, NULL, m_screen, NULL);
    // Lazy!
    SDL_Flip( m_screen );
    SDL_Delay( 2000 );
    SDL_FreeSurface(hello);
    return true;
}

bool st::_app::sdl::finish() {
    SDL_Quit();
    // Let's be honest, right now I don't care.
    return true;
}
<|endoftext|>


<commit_before>#include "./MediaDefinitions.h"
#include "rtp/SenderBandwidthEstimationHandler.h"

namespace erizo {

DEFINE_LOGGER(SenderBandwidthEstimationHandler, "rtp.SenderBandwidthEstimationHandler");

constexpr duration SenderBandwidthEstimationHandler::kMinUpdateEstimateInterval;

SenderBandwidthEstimationHandler::SenderBandwidthEstimationHandler(std::shared_ptr<Clock> the_clock) :
  connection_{nullptr}, bwe_listener_{nullptr}, clock_{the_clock}, initialized_{false}, enabled_{true},
  received_remb_{false}, period_packets_sent_{0}, estimated_bitrate_{0}, estimated_loss_{0},
  estimated_rtt_{0}, last_estimate_update_{clock::now()}, sender_bwe_{new SendSideBandwidthEstimation()} {
    sender_bwe_->SetSendBitrate(kStartSendBitrate);
  };

SenderBandwidthEstimationHandler::SenderBandwidthEstimationHandler(const SenderBandwidthEstimationHandler&& handler) :  // NOLINT
    connection_{handler.connection_},
    bwe_listener_{handler.bwe_listener_},
    clock_{handler.clock_},
    initialized_{handler.initialized_},
    enabled_{handler.enabled_},
    received_remb_{false},
    period_packets_sent_{handler.period_packets_sent_},
    estimated_bitrate_{handler.estimated_bitrate_},
    estimated_loss_{handler.estimated_loss_},
    estimated_rtt_{handler.estimated_rtt_},
    sender_bwe_{handler.sender_bwe_},
    sr_delay_data_{std::move(handler.sr_delay_data_)} {}

void SenderBandwidthEstimationHandler::enable() {
  enabled_ = true;
}

void SenderBandwidthEstimationHandler::disable() {
  enabled_ = false;
}

void SenderBandwidthEstimationHandler::notifyUpdate() {
  if (initialized_) {
    return;
  }
  auto pipeline = getContext()->getPipelineShared();
  if (pipeline && !connection_) {
    connection_ = pipeline->getService<WebRtcConnection>().get();
  }
  if (!connection_) {
    return;
  }
  stats_ = pipeline->getService<Stats>();
  if (!stats_) {
    return;
  }
  initialized_ = true;
}

void SenderBandwidthEstimationHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);
  if (chead->isFeedback()) {
    char* packet_pointer = packet->data;
    int rtcp_length = 0;
    int total_length = 0;
    int current_block = 0;

    do {
      packet_pointer+=rtcp_length;
      chead = reinterpret_cast<RtcpHeader*>(packet_pointer);
      rtcp_length = (ntohs(chead->length) + 1) * 4;
      total_length += rtcp_length;
      ELOG_DEBUG("%s ssrc %u, sourceSSRC %u, PacketType %u", connection_->toLog(),
          chead->getSSRC(),
          chead->getSourceSSRC(),
          chead->getPacketType());
      switch (chead->packettype) {
        case RTCP_Receiver_PT:
          {
            ELOG_DEBUG("%s, Analyzing Video RR: PacketLost %u, Ratio %u, current_block %d, blocks %d"
                ", sourceSSRC %u, ssrc %u",
                connection_->toLog(),
                chead->getLostPackets(),
                chead->getFractionLost(),
                current_block,
                chead->getBlockCount(),
                chead->getSourceSSRC(),
                chead->getSSRC());
            // calculate RTT + Update receiver block
            uint32_t delay_since_last_ms = (chead->getDelaySinceLastSr() * 1000) / 65536;
            int64_t now_ms = ClockUtils::timePointToMs(clock_->now());
            uint32_t last_sr = chead->getLastSr();

            auto value = std::find_if(sr_delay_data_.begin(), sr_delay_data_.end(),
                [last_sr](const std::shared_ptr<SrDelayData> sr_info) {
                return sr_info->sr_ntp == last_sr;
                });
            // TODO(pedro) Implement alternative when there are no REMBs
            if (received_remb_ && value != sr_delay_data_.end()) {
                uint32_t delay = now_ms - (*value)->sr_send_time - delay_since_last_ms;
                ELOG_DEBUG("%s message: Updating Estimate with RR, fraction_lost: %u, "
                    "delay: %u, period_packets_sent_: %u",
                    connection_->toLog(), chead->getFractionLost(), delay, period_packets_sent_);
                sender_bwe_->UpdateReceiverBlock(chead->getFractionLost(),
                    delay, period_packets_sent_, now_ms);
                period_packets_sent_ = 0;
                updateEstimate();
            }
          }
          break;
        case RTCP_PS_Feedback_PT:
          {
            if (chead->getBlockCount() == RTCP_AFB) {
              char *uniqueId = reinterpret_cast<char*>(&chead->report.rembPacket.uniqueid);
              if (!strncmp(uniqueId, "REMB", 4)) {
                received_remb_ = true;
                int64_t now_ms = ClockUtils::timePointToMs(clock_->now());
                uint64_t remb_bitrate =  chead->getBrMantis() << chead->getBrExp();
                uint64_t bitrate = estimated_bitrate_ != 0 ? estimated_bitrate_ : remb_bitrate;

                // We update the REMB with the latest estimation
                chead->setREMBBitRate(bitrate);
                ELOG_DEBUG("%s message: Updating estimate REMB, bitrate: %lu, estimated_bitrate %lu, remb_bitrate %lu",
                    connection_->toLog(), bitrate, estimated_bitrate_, remb_bitrate);
                sender_bwe_->UpdateReceiverEstimate(now_ms, remb_bitrate);
                updateEstimate();
              } else {
                ELOG_DEBUG("%s message: Unsupported AFB Packet not REMB", connection_->toLog());
              }
            }
          }
          break;
        default:
          break;
      }
      current_block++;
    } while (total_length < packet->length);
  }
  ctx->fireRead(std::move(packet));
}

void SenderBandwidthEstimationHandler::write(Context *ctx, std::shared_ptr<DataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);
  if (!chead->isRtcp() && packet->type == VIDEO_PACKET) {
    period_packets_sent_++;
    time_point now = clock_->now();
    if (received_remb_ && now - last_estimate_update_ > kMinUpdateEstimateInterval) {
      sender_bwe_->UpdateEstimate(ClockUtils::timePointToMs(now));
      updateEstimate();
      last_estimate_update_ = now;
    }
  } else if (chead->getPacketType() == RTCP_Sender_PT) {
    analyzeSr(chead);
  }
  ctx->fireWrite(std::move(packet));
}

void SenderBandwidthEstimationHandler::analyzeSr(RtcpHeader* chead) {
  uint64_t now = ClockUtils::timePointToMs(clock_->now());
  uint32_t ntp;
  ntp = chead->get32MiddleNtp();
  ELOG_DEBUG("%s message: adding incoming SR to list, ntp: %u", connection_->toLog(), ntp);
  sr_delay_data_.push_back(std::shared_ptr<SrDelayData>( new SrDelayData(ntp, now)));
  if (sr_delay_data_.size() >= kMaxSrListSize) {
    sr_delay_data_.pop_front();
  }
}

void SenderBandwidthEstimationHandler::updateEstimate() {
  sender_bwe_->CurrentEstimate(&estimated_bitrate_, &estimated_loss_,
      &estimated_rtt_);
  if (stats_) {
    stats_->getNode()["total"].insertStat("senderBitrateEstimation",
      CumulativeStat{static_cast<uint64_t>(estimated_bitrate_)});
  }
  ELOG_DEBUG("%s message: estimated bitrate %d, loss %u, rtt %ld",
      connection_->toLog(), estimated_bitrate_, estimated_loss_, estimated_rtt_);
  if (bwe_listener_) {
    bwe_listener_->onBandwidthEstimate(estimated_bitrate_, estimated_loss_, estimated_rtt_);
  }
}
}  // namespace erizo
<commit_msg>Also search REMBs and RRs after SRs (#1473)<commit_after>#include "./MediaDefinitions.h"
#include "rtp/SenderBandwidthEstimationHandler.h"

#include "rtp/RtpUtils.h"

namespace erizo {

DEFINE_LOGGER(SenderBandwidthEstimationHandler, "rtp.SenderBandwidthEstimationHandler");

constexpr duration SenderBandwidthEstimationHandler::kMinUpdateEstimateInterval;

SenderBandwidthEstimationHandler::SenderBandwidthEstimationHandler(std::shared_ptr<Clock> the_clock) :
  connection_{nullptr}, bwe_listener_{nullptr}, clock_{the_clock}, initialized_{false}, enabled_{true},
  received_remb_{false}, period_packets_sent_{0}, estimated_bitrate_{0}, estimated_loss_{0},
  estimated_rtt_{0}, last_estimate_update_{clock::now()}, sender_bwe_{new SendSideBandwidthEstimation()} {
    sender_bwe_->SetSendBitrate(kStartSendBitrate);
  };

SenderBandwidthEstimationHandler::SenderBandwidthEstimationHandler(const SenderBandwidthEstimationHandler&& handler) :  // NOLINT
    connection_{handler.connection_},
    bwe_listener_{handler.bwe_listener_},
    clock_{handler.clock_},
    initialized_{handler.initialized_},
    enabled_{handler.enabled_},
    received_remb_{false},
    period_packets_sent_{handler.period_packets_sent_},
    estimated_bitrate_{handler.estimated_bitrate_},
    estimated_loss_{handler.estimated_loss_},
    estimated_rtt_{handler.estimated_rtt_},
    sender_bwe_{handler.sender_bwe_},
    sr_delay_data_{std::move(handler.sr_delay_data_)} {}

void SenderBandwidthEstimationHandler::enable() {
  enabled_ = true;
}

void SenderBandwidthEstimationHandler::disable() {
  enabled_ = false;
}

void SenderBandwidthEstimationHandler::notifyUpdate() {
  if (initialized_) {
    return;
  }
  auto pipeline = getContext()->getPipelineShared();
  if (pipeline && !connection_) {
    connection_ = pipeline->getService<WebRtcConnection>().get();
  }
  if (!connection_) {
    return;
  }
  stats_ = pipeline->getService<Stats>();
  if (!stats_) {
    return;
  }
  initialized_ = true;
}

void SenderBandwidthEstimationHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) {
  RtpUtils::forEachRtcpBlock(packet, [this](RtcpHeader *chead) {
    ELOG_DEBUG("%s ssrc %u, sourceSSRC %u, PacketType %u", connection_->toLog(),
        chead->getSSRC(),
        chead->getSourceSSRC(),
        chead->getPacketType());
    switch (chead->packettype) {
      case RTCP_Receiver_PT:
        {
          // calculate RTT + Update receiver block
          uint32_t delay_since_last_ms = (chead->getDelaySinceLastSr() * 1000) / 65536;
          int64_t now_ms = ClockUtils::timePointToMs(clock_->now());
          uint32_t last_sr = chead->getLastSr();

          auto value = std::find_if(sr_delay_data_.begin(), sr_delay_data_.end(),
              [last_sr](const std::shared_ptr<SrDelayData> sr_info) {
              return sr_info->sr_ntp == last_sr;
              });
          ELOG_DEBUG("%s, Analyzing Video RR: PacketLost %u, Ratio %u, blocks %d"
              ", sourceSSRC %u, ssrc %u, last_sr %u, remb_received %d, found %d",
              connection_->toLog(),
              chead->getLostPackets(),
              chead->getFractionLost(),
              chead->getBlockCount(),
              chead->getSourceSSRC(),
              chead->getSSRC(),
              chead->getLastSr(),
              received_remb_,
              value != sr_delay_data_.end());
          // TODO(pedro) Implement alternative when there are no REMBs
          if (received_remb_ && value != sr_delay_data_.end()) {
              uint32_t delay = now_ms - (*value)->sr_send_time - delay_since_last_ms;
              ELOG_DEBUG("%s message: Updating Estimate with RR, fraction_lost: %u, "
                  "delay: %u, period_packets_sent_: %u",
                  connection_->toLog(), chead->getFractionLost(), delay, period_packets_sent_);
              sender_bwe_->UpdateReceiverBlock(chead->getFractionLost(),
                  delay, period_packets_sent_, now_ms);
              period_packets_sent_ = 0;
              updateEstimate();
          }
        }
        break;
      case RTCP_PS_Feedback_PT:
        {
          if (chead->getBlockCount() == RTCP_AFB) {
            char *uniqueId = reinterpret_cast<char*>(&chead->report.rembPacket.uniqueid);
            if (!strncmp(uniqueId, "REMB", 4)) {
              received_remb_ = true;
              int64_t now_ms = ClockUtils::timePointToMs(clock_->now());
              uint64_t remb_bitrate =  chead->getBrMantis() << chead->getBrExp();
              uint64_t bitrate = estimated_bitrate_ != 0 ? estimated_bitrate_ : remb_bitrate;

              // We update the REMB with the latest estimation
              chead->setREMBBitRate(bitrate);
              ELOG_DEBUG("%s message: Updating estimate REMB, bitrate: %lu, estimated_bitrate %lu, remb_bitrate %lu",
                  connection_->toLog(), bitrate, estimated_bitrate_, remb_bitrate);
              sender_bwe_->UpdateReceiverEstimate(now_ms, remb_bitrate);
              updateEstimate();
            } else {
              ELOG_DEBUG("%s message: Unsupported AFB Packet not REMB", connection_->toLog());
            }
          }
        }
        break;
      default:
        break;
    }
  });
  ctx->fireRead(std::move(packet));
}

void SenderBandwidthEstimationHandler::write(Context *ctx, std::shared_ptr<DataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);
  if (!chead->isRtcp() && packet->type == VIDEO_PACKET) {
    period_packets_sent_++;
    time_point now = clock_->now();
    if (received_remb_ && now - last_estimate_update_ > kMinUpdateEstimateInterval) {
      sender_bwe_->UpdateEstimate(ClockUtils::timePointToMs(now));
      updateEstimate();
      last_estimate_update_ = now;
    }
  } else if (chead->getPacketType() == RTCP_Sender_PT) {
    analyzeSr(chead);
  }
  ctx->fireWrite(std::move(packet));
}

void SenderBandwidthEstimationHandler::analyzeSr(RtcpHeader* chead) {
  uint64_t now = ClockUtils::timePointToMs(clock_->now());
  uint32_t ntp;
  ntp = chead->get32MiddleNtp();
  ELOG_DEBUG("%s message: adding incoming SR to list, ntp: %u", connection_->toLog(), ntp);
  sr_delay_data_.push_back(std::shared_ptr<SrDelayData>( new SrDelayData(ntp, now)));
  if (sr_delay_data_.size() >= kMaxSrListSize) {
    sr_delay_data_.pop_front();
  }
}

void SenderBandwidthEstimationHandler::updateEstimate() {
  sender_bwe_->CurrentEstimate(&estimated_bitrate_, &estimated_loss_,
      &estimated_rtt_);
  if (stats_) {
    stats_->getNode()["total"].insertStat("senderBitrateEstimation",
      CumulativeStat{static_cast<uint64_t>(estimated_bitrate_)});
  }
  ELOG_DEBUG("%s message: estimated bitrate %d, loss %u, rtt %ld",
      connection_->toLog(), estimated_bitrate_, estimated_loss_, estimated_rtt_);
  if (bwe_listener_) {
    bwe_listener_->onBandwidthEstimate(estimated_bitrate_, estimated_loss_, estimated_rtt_);
  }
}
}  // namespace erizo
<|endoftext|>


<commit_before>/* <x0/plugins/filter_example.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/http/HttpPlugin.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpResponse.h>
#include <x0/http/HttpRangeDef.h>
#include <x0/io/Filter.h>
#include <x0/strutils.h>
#include <x0/Types.h>
#include <x0/sysconfig.h>

// {{{ ExampleFilter
class ExampleFilter :
	public x0::Filter
{
	enum Mode {
		IDENTITY,
		UPPER,
		LOWER
	};

	Mode mode_;

public:
	explicit ExampleFilter(Mode mode);
	virtual x0::Buffer process(const x0::BufferRef& input);
};

ExampleFilter::ExampleFilter(Mode mode) : mode_(mode)
{
}

x0::Buffer ExampleFilter::process(const x0::BufferRef& input)
{
	x0::Buffer result;

	switch (mode_)
	{
		case ExampleFilter::LOWER:
			for (auto i = input.begin(), e = input.end(); i != e; ++i)
				result.push_back(static_cast<char>(std::tolower(*i)));
			break;
		case ExampleFilter::UPPER:
			for (auto i = input.begin(), e = input.end(); i != e; ++i)
				result.push_back(static_cast<char>(std::toupper(*i)));
			break;
		case ExampleFilter::IDENTITY:
		default:
			result.push_back(input);
	}

	return result;
}
// }}}

/**
 * \ingroup plugins
 * \brief ...
 */
class filter_plugin :
	public x0::HttpPlugin
{
public:
	filter_plugin(x0::HttpServer& srv, const std::string& name) :
		x0::HttpPlugin(srv, name)
	{
		registerFunction<filter_plugin, &filter_plugin::install_filter>("example_filter", Flow::Value::VOID);
	}

	~filter_plugin() {
	}

	void install_filter(Flow::Value& /*result*/, x0::HttpRequest *in, x0::HttpResponse *out, const x0::Params& args)
	{
		if (args.count() != 1) {
			log(x0::Severity::error, "No argument passed.");
			return;
		}

		if (!args[0].isString()) {
			log(x0::Severity::error, "Invalid argument type passed.");
			return;
		}

		if (strcmp(args[0].toString(), "identity") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::IDENTITY));
		else if (strcmp(args[0].toString(), "upper") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::UPPER));
		else if (strcmp(args[0].toString(), "lower") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::LOWER));
		else {
			log(x0::Severity::error, "Invalid argument value passed.");
			return;
		}

		out->headers.push_back("Content-Encoding", "filter_example");

		// response might change according to Accept-Encoding
		if (!out->headers.contains("Vary"))
			out->headers.push_back("Vary", "Accept-Encoding");
		else
			out->headers["Vary"] += ",Accept-Encoding";

		// removing content-length implicitely enables chunked encoding
		out->headers.remove("Content-Length");
	}
};

X0_EXPORT_PLUGIN(filter)
<commit_msg>brain-dead fix<commit_after>/* <x0/plugins/filter_example.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/http/HttpPlugin.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpResponse.h>
#include <x0/http/HttpRangeDef.h>
#include <x0/io/Filter.h>
#include <x0/strutils.h>
#include <x0/Types.h>
#include <x0/sysconfig.h>

// {{{ ExampleFilter
class ExampleFilter :
	public x0::Filter
{
public:
	enum Mode {
		IDENTITY,
		UPPER,
		LOWER
	};

private:
	Mode mode_;

public:
	explicit ExampleFilter(Mode mode);
	virtual x0::Buffer process(const x0::BufferRef& input);
};

ExampleFilter::ExampleFilter(Mode mode) : mode_(mode)
{
}

x0::Buffer ExampleFilter::process(const x0::BufferRef& input)
{
	x0::Buffer result;

	switch (mode_)
	{
		case ExampleFilter::LOWER:
			for (auto i = input.begin(), e = input.end(); i != e; ++i)
				result.push_back(static_cast<char>(std::tolower(*i)));
			break;
		case ExampleFilter::UPPER:
			for (auto i = input.begin(), e = input.end(); i != e; ++i)
				result.push_back(static_cast<char>(std::toupper(*i)));
			break;
		case ExampleFilter::IDENTITY:
		default:
			result.push_back(input);
	}

	return result;
}
// }}}

/**
 * \ingroup plugins
 * \brief ...
 */
class filter_plugin :
	public x0::HttpPlugin
{
public:
	filter_plugin(x0::HttpServer& srv, const std::string& name) :
		x0::HttpPlugin(srv, name)
	{
		registerFunction<filter_plugin, &filter_plugin::install_filter>("example_filter", Flow::Value::VOID);
	}

	~filter_plugin() {
	}

	void install_filter(Flow::Value& /*result*/, x0::HttpRequest *in, x0::HttpResponse *out, const x0::Params& args)
	{
		if (args.count() != 1) {
			log(x0::Severity::error, "No argument passed.");
			return;
		}

		if (!args[0].isString()) {
			log(x0::Severity::error, "Invalid argument type passed.");
			return;
		}

		if (strcmp(args[0].toString(), "identity") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::IDENTITY));
		else if (strcmp(args[0].toString(), "upper") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::UPPER));
		else if (strcmp(args[0].toString(), "lower") == 0)
			out->filters.push_back(std::make_shared<ExampleFilter>(ExampleFilter::LOWER));
		else {
			log(x0::Severity::error, "Invalid argument value passed.");
			return;
		}

		out->headers.push_back("Content-Encoding", "filter_example");

		// response might change according to Accept-Encoding
		if (!out->headers.contains("Vary"))
			out->headers.push_back("Vary", "Accept-Encoding");
		else
			out->headers["Vary"] += ",Accept-Encoding";

		// removing content-length implicitely enables chunked encoding
		out->headers.remove("Content-Length");
	}
};

X0_EXPORT_PLUGIN(filter)
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2007-2012 Tokutek Inc.  All rights reserved."
#ident "$Id$"

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <toku_assert.h>
#if defined(HAVE_MALLOC_H)
# include <malloc.h>
#elif defined(HAVE_SYS_MALLOC_H)
# include <sys/malloc.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#if defined(HAVE_SYSCALL_H)
# include <syscall.h>
#endif
#if defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h>
#endif
#if defined(HAVE_SYS_SYSCTL_H)
# include <sys/sysctl.h>
#endif
#if defined(HAVE_PTHREAD_NP_H)
# include <pthread_np.h>
#endif
#include <inttypes.h>
#include <sys/time.h>
#if defined(HAVE_SYS_RESOURCE_H)
# include <sys/resource.h>
#endif
#include <sys/statvfs.h>
#include "toku_portability.h"
#include "toku_os.h"
#include "toku_time.h"
#include "memory.h"

int
toku_portability_init(void) {
    int r = toku_memory_startup();
    return r;
}

void
toku_portability_destroy(void) {
    toku_memory_shutdown();
}

int
toku_os_getpid(void) {
    return getpid();
}

int
toku_os_gettid(void) {
#if defined(__NR_gettid)
    return syscall(__NR_gettid);
#elif defined(SYS_gettid)
    return syscall(SYS_gettid);
#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
    return pthread_getthreadid_np();
#else
# error "no implementation of gettid available"
#endif
}

int
toku_os_get_number_processors(void) {
    return sysconf(_SC_NPROCESSORS_CONF);
}

int
toku_os_get_number_active_processors(void) {
    int n = sysconf(_SC_NPROCESSORS_ONLN);
#define DO_TOKU_NCPUS 1
#if DO_TOKU_NCPUS
    {
        char *toku_ncpus = getenv("TOKU_NCPUS");
        if (toku_ncpus) {
            int ncpus = atoi(toku_ncpus);
            if (ncpus < n)
                n = ncpus;
        }
    }
#endif
    return n;
}

int
toku_os_get_pagesize(void) {
    return sysconf(_SC_PAGESIZE);
}

uint64_t
toku_os_get_phys_memory_size(void) {
#if defined(_SC_PHYS_PAGES)
    uint64_t npages = sysconf(_SC_PHYS_PAGES);
    uint64_t pagesize = sysconf(_SC_PAGESIZE);
    return npages*pagesize;
#elif defined(HAVE_SYS_SYSCTL_H)
    uint64_t memsize;
    size_t len = sizeof memsize;
    sysctlbyname("hw.memsize", &memsize, &len, NULL, 0);
    return memsize;
#else
# error "cannot find _SC_PHYS_PAGES or sysctlbyname()"
#endif
}

int
toku_os_get_file_size(int fildes, int64_t *fsize) {
    toku_struct_stat sbuf;
    int r = fstat(fildes, &sbuf);
    if (r==0) {
        *fsize = sbuf.st_size;
    }
    return r;
}

int
toku_os_get_unique_file_id(int fildes, struct fileid *id) {
    toku_struct_stat statbuf;
    memset(id, 0, sizeof(*id));
    int r=fstat(fildes, &statbuf);
    if (r==0) {
        id->st_dev = statbuf.st_dev;
        id->st_ino = statbuf.st_ino;
    }
    return r;
}

int
toku_os_lock_file(const char *name) {
    int r;
    int fd = open(name, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
    if (fd>=0) {
        r = flock(fd, LOCK_EX | LOCK_NB);
        if (r!=0) {
            r = errno; //Save errno from flock.
            close(fd);
            fd = -1; //Disable fd.
            errno = r;
        }
    }
    return fd;
}

int
toku_os_unlock_file(int fildes) {
    int r = flock(fildes, LOCK_UN);
    if (r==0) r = close(fildes);
    return r;
}

int
toku_os_mkdir(const char *pathname, mode_t mode) {
    int r = mkdir(pathname, mode);
    return r;
}

int
toku_os_get_process_times(struct timeval *usertime, struct timeval *kerneltime) {
    int r;
    struct rusage rusage;
    r = getrusage(RUSAGE_SELF, &rusage);
    if (r == -1)
        return get_error_errno();
    if (usertime)
        *usertime = rusage.ru_utime;
    if (kerneltime)
        *kerneltime = rusage.ru_stime;
    return 0;
}

int
toku_os_initialize_settings(int UU(verbosity)) {
    int r = 0;
    static int initialized = 0;
    assert(initialized==0);
    initialized=1;
    return r;
}

int
toku_os_get_max_rss(int64_t *maxrss) {
    char statusname[100];
    sprintf(statusname, "/proc/%d/status", getpid());
    FILE *f = fopen(statusname, "r");
    if (f == NULL) {
#if defined(HAVE_SYS_RESOURCE_H)
        // try getrusage instead
        struct rusage rusage;
        getrusage(RUSAGE_SELF, &rusage);
        *maxrss = rusage.ru_maxrss * 1024; // ru_maxrss is in kB
        return 0;
#else
        return get_error_errno();
#endif
    }
    int r = ENOENT;
    char line[100];
    while (fgets(line, sizeof line, f)) {
        r = sscanf(line, "VmHWM:\t%lld kB\n", (long long *) maxrss);
        if (r == 1) {
            *maxrss *= 1<<10;
            r = 0;
            break;
        }
    }
    fclose(f);
    return r;
}

int
toku_os_get_rss(int64_t *rss) {
    char statusname[100];
    sprintf(statusname, "/proc/%d/status", getpid());
    FILE *f = fopen(statusname, "r");
    if (f == NULL) {
#if defined(HAVE_SYS_RESOURCE_H)
        // try getrusage instead
        struct rusage rusage;
        getrusage(RUSAGE_SELF, &rusage);
        *rss = (rusage.ru_idrss + rusage.ru_ixrss + rusage.ru_isrss) * 1024;
        return 0;
#else
        return get_error_errno();
#endif
    }
    int r = ENOENT;
    char line[100];
    while (fgets(line, sizeof line, f)) {
        r = sscanf(line, "VmRSS:\t%lld kB\n", (long long *) rss);
        if (r == 1) {
            *rss *= 1<<10;
            r = 0;
            break;
        }
    }
    fclose(f);
    return r;
}

bool toku_os_is_absolute_name(const char* path) {
    return path[0] == '/';
}

int
toku_os_get_max_process_data_size(uint64_t *maxdata) {
    int r;
    struct rlimit rlimit;

    r = getrlimit(RLIMIT_DATA, &rlimit);
    if (r == 0) {
        uint64_t d;
        d = rlimit.rlim_max;
	// with the "right" macros defined, the rlimit is a 64 bit number on a
	// 32 bit system.  getrlimit returns 2**64-1 which is clearly wrong.

        // for 32 bit processes, we assume that 1/2 of the address space is
        // used for mapping the kernel.  this may be pessimistic.
        if (sizeof (void *) == 4 && d > (1ULL << 31))
            d = 1ULL << 31;
	*maxdata = d;
    } else
        r = get_error_errno();
    return r;
}

int
toku_stat(const char *name, toku_struct_stat *buf) {
    int r = stat(name, buf);
    return r;
}

int
toku_fstat(int fd, toku_struct_stat *buf) {
    int r = fstat(fd, buf);
    return r;
}

static int
toku_get_processor_frequency_sys(uint64_t *hzret) {
    int r;
    FILE *fp = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
    if (!fp)
        r = get_error_errno();
    else {
        unsigned int khz = 0;
        if (fscanf(fp, "%u", &khz) == 1) {
            *hzret = khz * 1000ULL;
            r = 0;
        } else
            r = ENOENT;
        fclose(fp);
    }
    return r;
}

static int
toku_get_processor_frequency_cpuinfo(uint64_t *hzret) {
    int r;
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if (!fp) {
        r = get_error_errno();
    } else {
        uint64_t maxhz = 0;
        char *buf = NULL;
        size_t n = 0;
        while (getline(&buf, &n, fp) >= 0) {
            unsigned int cpu;
            sscanf(buf, "processor : %u", &cpu);
            unsigned int ma, mb;
            if (sscanf(buf, "cpu MHz : %u.%u", &ma, &mb) == 2) {
                uint64_t hz = ma * 1000000ULL + mb * 1000ULL;
                if (hz > maxhz)
                    maxhz = hz;
            }
        }
        if (buf)
            free(buf);
        fclose(fp);
        *hzret = maxhz;
        r = maxhz == 0 ? ENOENT : 0;;
    }
    return r;
}

static int
toku_get_processor_frequency_sysctl(const char * const cmd, uint64_t *hzret) {
    int r = 0;
    FILE *fp = popen(cmd, "r");
    if (!fp) {
        r = EINVAL;  // popen doesn't return anything useful in errno,
                     // gotta pick something
        goto exit;
    }
    r = fscanf(fp, "%" SCNu64, hzret);
    if (r != 1) {
        r = get_maybe_error_errno();
    } else {
        r = 0;
    }
    pclose(fp);

exit:
    return r;
}

int
toku_os_get_processor_frequency(uint64_t *hzret) {
    int r;
    r = toku_get_processor_frequency_sys(hzret);
    if (r != 0)
        r = toku_get_processor_frequency_cpuinfo(hzret);
    if (r != 0)
        r = toku_get_processor_frequency_sysctl("sysctl -n hw.cpufrequency", hzret);
    if (r != 0)
        r = toku_get_processor_frequency_sysctl("sysctl -n machdep.tsc_freq", hzret);
    return r;
}

int
toku_get_filesystem_sizes(const char *path, uint64_t *avail_size, uint64_t *free_size, uint64_t *total_size) {
    struct statvfs s;
    int r = statvfs(path, &s);
    if (r == -1) {
        r = get_error_errno();
    } else {
        // get the block size in bytes
        uint64_t bsize = s.f_frsize ? s.f_frsize : s.f_bsize;
        // convert blocks to bytes
        if (avail_size)
            *avail_size = (uint64_t) s.f_bavail * bsize;
        if (free_size)
            *free_size = (uint64_t) s.f_bfree * bsize;
        if (total_size)
            *total_size = (uint64_t) s.f_blocks * bsize;
    }
    return r;
}

int
toku_dup2(int fd, int fd2) {
    int r;
    r = dup2(fd, fd2);
    return r;
}

// Time
static       double seconds_per_clock = -1;

double tokutime_to_seconds(tokutime_t t) {
    // Convert tokutime to seconds.
    if (seconds_per_clock<0) {
	uint64_t hz;
	int r = toku_os_get_processor_frequency(&hz);
	assert(r==0);
	// There's a race condition here, but it doesn't really matter.  If two threads call tokutime_to_seconds
	// for the first time at the same time, then both will fetch the value and set the same value.
	seconds_per_clock = 1.0/hz;
    }
    return t*seconds_per_clock;
}

#if __GNUC__ && __i386__

// workaround for a gcc 4.1.2 bug on 32 bit platforms.
uint64_t toku_sync_fetch_and_add_uint64(volatile uint64_t *a, uint64_t b) __attribute__((noinline));

uint64_t toku_sync_fetch_and_add_uint64(volatile uint64_t *a, uint64_t b) {
    return __sync_fetch_and_add(a, b);
}

#endif
<commit_msg>refs #5368 clean up toku_os_get_*rss<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2007-2012 Tokutek Inc.  All rights reserved."
#ident "$Id$"

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <toku_assert.h>
#if defined(HAVE_MALLOC_H)
# include <malloc.h>
#elif defined(HAVE_SYS_MALLOC_H)
# include <sys/malloc.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#if defined(HAVE_SYSCALL_H)
# include <syscall.h>
#endif
#if defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h>
#endif
#if defined(HAVE_SYS_SYSCTL_H)
# include <sys/sysctl.h>
#endif
#if defined(HAVE_PTHREAD_NP_H)
# include <pthread_np.h>
#endif
#include <inttypes.h>
#include <sys/time.h>
#if defined(HAVE_SYS_RESOURCE_H)
# include <sys/resource.h>
#endif
#include <sys/statvfs.h>
#include "toku_portability.h"
#include "toku_os.h"
#include "toku_time.h"
#include "memory.h"

int
toku_portability_init(void) {
    int r = toku_memory_startup();
    return r;
}

void
toku_portability_destroy(void) {
    toku_memory_shutdown();
}

int
toku_os_getpid(void) {
    return getpid();
}

int
toku_os_gettid(void) {
#if defined(__NR_gettid)
    return syscall(__NR_gettid);
#elif defined(SYS_gettid)
    return syscall(SYS_gettid);
#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
    return pthread_getthreadid_np();
#else
# error "no implementation of gettid available"
#endif
}

int
toku_os_get_number_processors(void) {
    return sysconf(_SC_NPROCESSORS_CONF);
}

int
toku_os_get_number_active_processors(void) {
    int n = sysconf(_SC_NPROCESSORS_ONLN);
#define DO_TOKU_NCPUS 1
#if DO_TOKU_NCPUS
    {
        char *toku_ncpus = getenv("TOKU_NCPUS");
        if (toku_ncpus) {
            int ncpus = atoi(toku_ncpus);
            if (ncpus < n)
                n = ncpus;
        }
    }
#endif
    return n;
}

int
toku_os_get_pagesize(void) {
    return sysconf(_SC_PAGESIZE);
}

uint64_t
toku_os_get_phys_memory_size(void) {
#if defined(_SC_PHYS_PAGES)
    uint64_t npages = sysconf(_SC_PHYS_PAGES);
    uint64_t pagesize = sysconf(_SC_PAGESIZE);
    return npages*pagesize;
#elif defined(HAVE_SYS_SYSCTL_H)
    uint64_t memsize;
    size_t len = sizeof memsize;
    sysctlbyname("hw.memsize", &memsize, &len, NULL, 0);
    return memsize;
#else
# error "cannot find _SC_PHYS_PAGES or sysctlbyname()"
#endif
}

int
toku_os_get_file_size(int fildes, int64_t *fsize) {
    toku_struct_stat sbuf;
    int r = fstat(fildes, &sbuf);
    if (r==0) {
        *fsize = sbuf.st_size;
    }
    return r;
}

int
toku_os_get_unique_file_id(int fildes, struct fileid *id) {
    toku_struct_stat statbuf;
    memset(id, 0, sizeof(*id));
    int r=fstat(fildes, &statbuf);
    if (r==0) {
        id->st_dev = statbuf.st_dev;
        id->st_ino = statbuf.st_ino;
    }
    return r;
}

int
toku_os_lock_file(const char *name) {
    int r;
    int fd = open(name, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
    if (fd>=0) {
        r = flock(fd, LOCK_EX | LOCK_NB);
        if (r!=0) {
            r = errno; //Save errno from flock.
            close(fd);
            fd = -1; //Disable fd.
            errno = r;
        }
    }
    return fd;
}

int
toku_os_unlock_file(int fildes) {
    int r = flock(fildes, LOCK_UN);
    if (r==0) r = close(fildes);
    return r;
}

int
toku_os_mkdir(const char *pathname, mode_t mode) {
    int r = mkdir(pathname, mode);
    return r;
}

int
toku_os_get_process_times(struct timeval *usertime, struct timeval *kerneltime) {
    int r;
    struct rusage rusage;
    r = getrusage(RUSAGE_SELF, &rusage);
    if (r == -1)
        return get_error_errno();
    if (usertime)
        *usertime = rusage.ru_utime;
    if (kerneltime)
        *kerneltime = rusage.ru_stime;
    return 0;
}

int
toku_os_initialize_settings(int UU(verbosity)) {
    int r = 0;
    static int initialized = 0;
    assert(initialized==0);
    initialized=1;
    return r;
}

int
toku_os_get_max_rss(int64_t *maxrss) {
    int r;
    char statusname[100];
    sprintf(statusname, "/proc/%d/status", getpid());
    FILE *f = fopen(statusname, "r");
    if (f == NULL) {
        struct rusage rusage;
        r = getrusage(RUSAGE_SELF, &rusage);
        if (r != 0) {
            return get_error_errno();
        }
        *maxrss = rusage.ru_maxrss * 1024; // ru_maxrss is in kB
        return 0;
    }
    r = ENOENT;
    char line[100];
    while (fgets(line, sizeof line, f)) {
        r = sscanf(line, "VmHWM:\t%lld kB\n", (long long *) maxrss);
        if (r == 1) {
            *maxrss *= 1<<10;
            r = 0;
            break;
        }
    }
    fclose(f);
    return r;
}

int
toku_os_get_rss(int64_t *rss) {
    int r;
    char statusname[100];
    sprintf(statusname, "/proc/%d/status", getpid());
    FILE *f = fopen(statusname, "r");
    if (f == NULL) {
        struct rusage rusage;
        r = getrusage(RUSAGE_SELF, &rusage);
        if (r != 0) {
            return get_error_errno();
        }
        *rss = (rusage.ru_idrss + rusage.ru_ixrss + rusage.ru_isrss) * 1024;
        return 0;
    }
    r = ENOENT;
    char line[100];
    while (fgets(line, sizeof line, f)) {
        r = sscanf(line, "VmRSS:\t%lld kB\n", (long long *) rss);
        if (r == 1) {
            *rss *= 1<<10;
            r = 0;
            break;
        }
    }
    fclose(f);
    return r;
}

bool toku_os_is_absolute_name(const char* path) {
    return path[0] == '/';
}

int
toku_os_get_max_process_data_size(uint64_t *maxdata) {
    int r;
    struct rlimit rlimit;

    r = getrlimit(RLIMIT_DATA, &rlimit);
    if (r == 0) {
        uint64_t d;
        d = rlimit.rlim_max;
	// with the "right" macros defined, the rlimit is a 64 bit number on a
	// 32 bit system.  getrlimit returns 2**64-1 which is clearly wrong.

        // for 32 bit processes, we assume that 1/2 of the address space is
        // used for mapping the kernel.  this may be pessimistic.
        if (sizeof (void *) == 4 && d > (1ULL << 31))
            d = 1ULL << 31;
	*maxdata = d;
    } else
        r = get_error_errno();
    return r;
}

int
toku_stat(const char *name, toku_struct_stat *buf) {
    int r = stat(name, buf);
    return r;
}

int
toku_fstat(int fd, toku_struct_stat *buf) {
    int r = fstat(fd, buf);
    return r;
}

static int
toku_get_processor_frequency_sys(uint64_t *hzret) {
    int r;
    FILE *fp = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
    if (!fp)
        r = get_error_errno();
    else {
        unsigned int khz = 0;
        if (fscanf(fp, "%u", &khz) == 1) {
            *hzret = khz * 1000ULL;
            r = 0;
        } else
            r = ENOENT;
        fclose(fp);
    }
    return r;
}

static int
toku_get_processor_frequency_cpuinfo(uint64_t *hzret) {
    int r;
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if (!fp) {
        r = get_error_errno();
    } else {
        uint64_t maxhz = 0;
        char *buf = NULL;
        size_t n = 0;
        while (getline(&buf, &n, fp) >= 0) {
            unsigned int cpu;
            sscanf(buf, "processor : %u", &cpu);
            unsigned int ma, mb;
            if (sscanf(buf, "cpu MHz : %u.%u", &ma, &mb) == 2) {
                uint64_t hz = ma * 1000000ULL + mb * 1000ULL;
                if (hz > maxhz)
                    maxhz = hz;
            }
        }
        if (buf)
            free(buf);
        fclose(fp);
        *hzret = maxhz;
        r = maxhz == 0 ? ENOENT : 0;;
    }
    return r;
}

static int
toku_get_processor_frequency_sysctl(const char * const cmd, uint64_t *hzret) {
    int r = 0;
    FILE *fp = popen(cmd, "r");
    if (!fp) {
        r = EINVAL;  // popen doesn't return anything useful in errno,
                     // gotta pick something
        goto exit;
    }
    r = fscanf(fp, "%" SCNu64, hzret);
    if (r != 1) {
        r = get_maybe_error_errno();
    } else {
        r = 0;
    }
    pclose(fp);

exit:
    return r;
}

int
toku_os_get_processor_frequency(uint64_t *hzret) {
    int r;
    r = toku_get_processor_frequency_sys(hzret);
    if (r != 0)
        r = toku_get_processor_frequency_cpuinfo(hzret);
    if (r != 0)
        r = toku_get_processor_frequency_sysctl("sysctl -n hw.cpufrequency", hzret);
    if (r != 0)
        r = toku_get_processor_frequency_sysctl("sysctl -n machdep.tsc_freq", hzret);
    return r;
}

int
toku_get_filesystem_sizes(const char *path, uint64_t *avail_size, uint64_t *free_size, uint64_t *total_size) {
    struct statvfs s;
    int r = statvfs(path, &s);
    if (r == -1) {
        r = get_error_errno();
    } else {
        // get the block size in bytes
        uint64_t bsize = s.f_frsize ? s.f_frsize : s.f_bsize;
        // convert blocks to bytes
        if (avail_size)
            *avail_size = (uint64_t) s.f_bavail * bsize;
        if (free_size)
            *free_size = (uint64_t) s.f_bfree * bsize;
        if (total_size)
            *total_size = (uint64_t) s.f_blocks * bsize;
    }
    return r;
}

int
toku_dup2(int fd, int fd2) {
    int r;
    r = dup2(fd, fd2);
    return r;
}

// Time
static       double seconds_per_clock = -1;

double tokutime_to_seconds(tokutime_t t) {
    // Convert tokutime to seconds.
    if (seconds_per_clock<0) {
	uint64_t hz;
	int r = toku_os_get_processor_frequency(&hz);
	assert(r==0);
	// There's a race condition here, but it doesn't really matter.  If two threads call tokutime_to_seconds
	// for the first time at the same time, then both will fetch the value and set the same value.
	seconds_per_clock = 1.0/hz;
    }
    return t*seconds_per_clock;
}

#if __GNUC__ && __i386__

// workaround for a gcc 4.1.2 bug on 32 bit platforms.
uint64_t toku_sync_fetch_and_add_uint64(volatile uint64_t *a, uint64_t b) __attribute__((noinline));

uint64_t toku_sync_fetch_and_add_uint64(volatile uint64_t *a, uint64_t b) {
    return __sync_fetch_and_add(a, b);
}

#endif
<|endoftext|>


<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_UTILITIES_HPP_
#define POSEIDON_UTILITIES_HPP_

#include "fwd.hpp"
#include "static/async_logger.hpp"
#include "core/abstract_timer.hpp"
#include "static/timer_driver.hpp"
#include <asteria/utilities.hpp>
#include <cstdio>

namespace poseidon {

using ::asteria::utf8_encode;
using ::asteria::utf8_decode;
using ::asteria::utf16_encode;
using ::asteria::utf16_decode;

using ::asteria::format_string;
using ::asteria::weaken_enum;
using ::asteria::generate_random_seed;
using ::asteria::format_errno;

template<typename... ParamsT>
ROCKET_NOINLINE
bool
do_xlog_format(Log_Level level, const char* file, long line, const char* func,
               const char* templ, const ParamsT&... params)
noexcept
  try {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    Async_Logger::write(level, file, line, func, ::std::move(text));
    return true;
  }
  catch(exception& stdex) {
    // Ignore this exception, but print a message.
    ::std::fprintf(stderr,
        "WARNING: %s: could not format log: %s\n[exception `%s` thrown from '%s:%ld'\n",
        func, stdex.what(), typeid(stdex).name(), file, line);
    return false;
  }

// Note the format string must be a string literal.
#define POSEIDON_XLOG_(level, ...)  \
    (::poseidon::Async_Logger::is_enabled(level) &&  \
         ::poseidon::do_xlog_format(level, __FILE__, __LINE__, __func__,  \
                                    "" __VA_ARGS__))

#define POSEIDON_LOG_FATAL(...)   POSEIDON_XLOG_(::poseidon::log_level_fatal,  __VA_ARGS__)
#define POSEIDON_LOG_ERROR(...)   POSEIDON_XLOG_(::poseidon::log_level_error,  __VA_ARGS__)
#define POSEIDON_LOG_WARN(...)    POSEIDON_XLOG_(::poseidon::log_level_warn,   __VA_ARGS__)
#define POSEIDON_LOG_INFO(...)    POSEIDON_XLOG_(::poseidon::log_level_info,   __VA_ARGS__)
#define POSEIDON_LOG_DEBUG(...)   POSEIDON_XLOG_(::poseidon::log_level_debug,  __VA_ARGS__)
#define POSEIDON_LOG_TRACE(...)   POSEIDON_XLOG_(::poseidon::log_level_trace,  __VA_ARGS__)

template<typename... ParamsT>
[[noreturn]] ROCKET_NOINLINE
bool
do_xthrow_format(const char* file, long line, const char* func,
                 const char* templ, const ParamsT&... params)
  {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    if(Async_Logger::is_enabled(log_level_warn))
      Async_Logger::write(log_level_warn, file, line, func, text);

    // Throw the exception.
    ::rocket::sprintf_and_throw<::std::runtime_error>(
        "%s: %s\n[thrown from '%s:%ld']",
        func, text.c_str(), file, line);
  }

#define POSEIDON_THROW(...)  \
    (::poseidon::do_xthrow_format(__FILE__, __LINE__, __func__,  \
                                  "" __VA_ARGS__))

// Creates an asynchronous timer. The timer function will be called by
// the timer thread, so thread safety must be taken into account.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer(int64_t next, int64_t period, FuncT&& func)
  {
    // This is the concrete timer class.
    struct Concrete_Timer : Abstract_Timer
      {
        typename ::std::decay<FuncT>::type m_func;

        Concrete_Timer(int64_t next, int64_t period, FuncT&& func)
          : Abstract_Timer(next, period),
            m_func(::std::forward<FuncT>(func))
          { }

        void
        do_on_async_timer(int64_t now)
        override
          { this->m_func(now);  }
      };

    // Allocate an abstract timer and insert it.
    auto timer = ::rocket::make_unique<Concrete_Timer>(next, period,
                                                       ::std::forward<FuncT>(func));
    return Timer_Driver::insert(::std::move(timer));
  }

// Creates a one-shot timer. The timer is deleted after being triggered.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_oneshot(int64_t next, FuncT&& func)
  {
    return noadl::create_async_timer(next, 0, ::std::forward<FuncT>(func));
  }

// Creates a periodic timer.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_periodic(int64_t period, FuncT&& func)
  {
    return noadl::create_async_timer(period, period, ::std::forward<FuncT>(func));
  }

}  // namespace asteria

#endif
<commit_msg>utilities: Change log level of exceptions from WARN to DEBUG<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_UTILITIES_HPP_
#define POSEIDON_UTILITIES_HPP_

#include "fwd.hpp"
#include "static/async_logger.hpp"
#include "core/abstract_timer.hpp"
#include "static/timer_driver.hpp"
#include <asteria/utilities.hpp>
#include <cstdio>

namespace poseidon {

using ::asteria::utf8_encode;
using ::asteria::utf8_decode;
using ::asteria::utf16_encode;
using ::asteria::utf16_decode;

using ::asteria::format_string;
using ::asteria::weaken_enum;
using ::asteria::generate_random_seed;
using ::asteria::format_errno;

template<typename... ParamsT>
ROCKET_NOINLINE
bool
do_xlog_format(Log_Level level, const char* file, long line, const char* func,
               const char* templ, const ParamsT&... params)
noexcept
  try {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    Async_Logger::write(level, file, line, func, ::std::move(text));
    return true;
  }
  catch(exception& stdex) {
    // Ignore this exception, but print a message.
    ::std::fprintf(stderr,
        "WARNING: %s: could not format log: %s\n[exception `%s` thrown from '%s:%ld'\n",
        func, stdex.what(), typeid(stdex).name(), file, line);
    return false;
  }

// Note the format string must be a string literal.
#define POSEIDON_XLOG_(level, ...)  \
    (::poseidon::Async_Logger::is_enabled(level) &&  \
         ::poseidon::do_xlog_format(level, __FILE__, __LINE__, __func__,  \
                                    "" __VA_ARGS__))

#define POSEIDON_LOG_FATAL(...)   POSEIDON_XLOG_(::poseidon::log_level_fatal,  __VA_ARGS__)
#define POSEIDON_LOG_ERROR(...)   POSEIDON_XLOG_(::poseidon::log_level_error,  __VA_ARGS__)
#define POSEIDON_LOG_WARN(...)    POSEIDON_XLOG_(::poseidon::log_level_warn,   __VA_ARGS__)
#define POSEIDON_LOG_INFO(...)    POSEIDON_XLOG_(::poseidon::log_level_info,   __VA_ARGS__)
#define POSEIDON_LOG_DEBUG(...)   POSEIDON_XLOG_(::poseidon::log_level_debug,  __VA_ARGS__)
#define POSEIDON_LOG_TRACE(...)   POSEIDON_XLOG_(::poseidon::log_level_trace,  __VA_ARGS__)

template<typename... ParamsT>
[[noreturn]] ROCKET_NOINLINE
bool
do_xthrow_format(const char* file, long line, const char* func,
                 const char* templ, const ParamsT&... params)
  {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    if(Async_Logger::is_enabled(log_level_debug))
      Async_Logger::write(log_level_debug, file, line, func, text);

    // Throw the exception.
    ::rocket::sprintf_and_throw<::std::runtime_error>(
        "%s: %s\n[thrown from '%s:%ld']",
        func, text.c_str(), file, line);
  }

#define POSEIDON_THROW(...)  \
    (::poseidon::do_xthrow_format(__FILE__, __LINE__, __func__,  \
                                  "" __VA_ARGS__))

// Creates an asynchronous timer. The timer function will be called by
// the timer thread, so thread safety must be taken into account.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer(int64_t next, int64_t period, FuncT&& func)
  {
    // This is the concrete timer class.
    struct Concrete_Timer : Abstract_Timer
      {
        typename ::std::decay<FuncT>::type m_func;

        Concrete_Timer(int64_t next, int64_t period, FuncT&& func)
          : Abstract_Timer(next, period),
            m_func(::std::forward<FuncT>(func))
          { }

        void
        do_on_async_timer(int64_t now)
        override
          { this->m_func(now);  }
      };

    // Allocate an abstract timer and insert it.
    auto timer = ::rocket::make_unique<Concrete_Timer>(next, period,
                                                       ::std::forward<FuncT>(func));
    return Timer_Driver::insert(::std::move(timer));
  }

// Creates a one-shot timer. The timer is deleted after being triggered.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_oneshot(int64_t next, FuncT&& func)
  {
    return noadl::create_async_timer(next, 0, ::std::forward<FuncT>(func));
  }

// Creates a periodic timer.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_periodic(int64_t period, FuncT&& func)
  {
    return noadl::create_async_timer(period, period, ::std::forward<FuncT>(func));
  }

}  // namespace asteria

#endif
<|endoftext|>