<commit_before>#include "kinc.h"
#include <mcheck.h>

/**
 * Prints the command-line usage instructions for the similarity command
 */
void print_usage() {
  printf("\n");
  printf("Usage: ./kinc [command]\n");
  printf("Available commands:\n");
  printf("  similarity       Performs pair-wise similarity calculations using an input expression matrix.\n");
  printf("  threshold        Identifies a threshold for cutting the similarity matrix\n");
  printf("  extract          Outputs the network edges file\n");
  printf("  help [command]   Prints these instructions. Include the command to print help\n");
  printf("                   for a specific command (e.g. kinc help similarity)\n");
  printf("\n");
}

/**
 * The main subroutine.  Parses the input parameters and executes the program
 * accordingly.
 */
int main(int argc, char *argv[]) {
  // Enable mtrace memory leak checking
  mtrace();

  // The return value
  int retval = 0;

  // make sure we have at least one input argument for the command
  if (argc == 1) {
    printf("ERROR: Please provide the command to execute.\n\n");
    print_usage();
    retval = -1;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "similarity") == 0) {
    RunSimilarity * similarity = new RunSimilarity(argc, argv);
    similarity->execute();
    delete similarity;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "index") == 0) {
    RunIndex * index = new RunIndex(argc, argv);
    index->execute();
    delete index;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "query") == 0) {
    RunQuery * query = new RunQuery(argc, argv);
    query->execute();
    delete query;
  }
  // identify the threshold for cutting the similarity matrix
  else if (strcmp(argv[1], "threshold") == 0) {
    RunThreshold * threshold = new RunThreshold(argc, argv);
    threshold->execute();
    delete threshold;
  }
  // extract a given element from the matrix or a network
  else if (strcmp(argv[1], "extract") == 0) {
    RunExtract * extract = new RunExtract(argc, argv);
    extract->execute();
    delete extract;
  }
  // print help documentation
  else if (strcmp(argv[1], "help") == 0) {
    if (argc == 3) {
      if (strcmp(argv[2], "similarity") == 0) {
        RunSimilarity::printUsage();
      }
      if (strcmp(argv[2], "threshold") == 0) {
        RunThreshold::printUsage();
      }
      if (strcmp(argv[2], "extract") == 0) {
        RunExtract::printUsage();
      }
      if (strcmp(argv[2], "index") == 0) {
        RunIndex::printUsage();
      }
      if (strcmp(argv[2], "query") == 0) {
        RunQuery::printUsage();
      }
    }
    else {
      print_usage();
    }
  }
  else {
    printf("ERROR: Unknown command.\n\n");
    print_usage();
    retval = -1;
  }

  return retval;
}

/**
 *
 */
void start_mpi() {

  //  // MPI variables
  //  int mpi_err, mpi_num_procs, mpi_id;
  //
  //  // Initialize MPI.
  //  mpi_err = MPI_Init(&argc, &argv);
  //
  //  // Find out my process ID, and how many processes were started.
  //  mpi_err |= MPI_Comm_rank(MPI_COMM_WORLD, &mpi_id);
  //  mpi_err |= MPI_Comm_size(MPI_COMM_WORLD, &mpi_num_procs);
  //
  //  if (mpi_err != 0) {
  //    printf("MPI initialization failed\n");
  //    exit(1);
  //  }

    // For testing a single process... should comment out when not testing.
  //  if (mpi_id + 1 != 5) {
  //    mpi_err = MPI_Finalize();
  //    return 1;
  //  }

  //  printf("Using %i out of %i processes.\n", mpi_id + 1, mpi_num_procs);
}

/**
 *
 */
void end_mpi() {
  // Wait until all other processes are completed before closing the manager
//  MPI_Status stat;
//  char message[10];
//  if (mpi_id > 0 ) {
//    // All non master processes should report done when completed.
//    sprintf(message, "Done");
//    MPI_Send(message, strlen(message)+1, MPI_BYTE, 0,1,MPI_COMM_WORLD);
//  }
//  else {
//    // The master process should wait to get 'Done' from each process
//    // before terminating
//    int proc;
//    for (proc = 1; proc < mpi_num_procs; proc++) {
//      MPI_Recv(message, sizeof(message), MPI_BYTE, proc, 1, MPI_COMM_WORLD, &stat);
//    }
//  }
//
//  // Terminate MPI.
//  mpi_err = MPI_Finalize();
}

<commit_msg>Forgot to remove mtrace line<commit_after>#include "kinc.h"
#include <mcheck.h>

/**
 * Prints the command-line usage instructions for the similarity command
 */
void print_usage() {
  printf("\n");
  printf("Usage: ./kinc [command]\n");
  printf("Available commands:\n");
  printf("  similarity       Performs pair-wise similarity calculations using an input expression matrix.\n");
  printf("  threshold        Identifies a threshold for cutting the similarity matrix\n");
  printf("  extract          Outputs the network edges file\n");
  printf("  help [command]   Prints these instructions. Include the command to print help\n");
  printf("                   for a specific command (e.g. kinc help similarity)\n");
  printf("\n");
}

/**
 * The main subroutine.  Parses the input parameters and executes the program
 * accordingly.
 */
int main(int argc, char *argv[]) {
  // Enable mtrace memory leak checking
  //mtrace();

  // The return value
  int retval = 0;

  // make sure we have at least one input argument for the command
  if (argc == 1) {
    printf("ERROR: Please provide the command to execute.\n\n");
    print_usage();
    retval = -1;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "similarity") == 0) {
    RunSimilarity * similarity = new RunSimilarity(argc, argv);
    similarity->execute();
    delete similarity;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "index") == 0) {
    RunIndex * index = new RunIndex(argc, argv);
    index->execute();
    delete index;
  }
  // construct the similarity matrix
  else if (strcmp(argv[1], "query") == 0) {
    RunQuery * query = new RunQuery(argc, argv);
    query->execute();
    delete query;
  }
  // identify the threshold for cutting the similarity matrix
  else if (strcmp(argv[1], "threshold") == 0) {
    RunThreshold * threshold = new RunThreshold(argc, argv);
    threshold->execute();
    delete threshold;
  }
  // extract a given element from the matrix or a network
  else if (strcmp(argv[1], "extract") == 0) {
    RunExtract * extract = new RunExtract(argc, argv);
    extract->execute();
    delete extract;
  }
  // print help documentation
  else if (strcmp(argv[1], "help") == 0) {
    if (argc == 3) {
      if (strcmp(argv[2], "similarity") == 0) {
        RunSimilarity::printUsage();
      }
      if (strcmp(argv[2], "threshold") == 0) {
        RunThreshold::printUsage();
      }
      if (strcmp(argv[2], "extract") == 0) {
        RunExtract::printUsage();
      }
      if (strcmp(argv[2], "index") == 0) {
        RunIndex::printUsage();
      }
      if (strcmp(argv[2], "query") == 0) {
        RunQuery::printUsage();
      }
    }
    else {
      print_usage();
    }
  }
  else {
    printf("ERROR: Unknown command.\n\n");
    print_usage();
    retval = -1;
  }

  return retval;
}

/**
 *
 */
void start_mpi() {

  //  // MPI variables
  //  int mpi_err, mpi_num_procs, mpi_id;
  //
  //  // Initialize MPI.
  //  mpi_err = MPI_Init(&argc, &argv);
  //
  //  // Find out my process ID, and how many processes were started.
  //  mpi_err |= MPI_Comm_rank(MPI_COMM_WORLD, &mpi_id);
  //  mpi_err |= MPI_Comm_size(MPI_COMM_WORLD, &mpi_num_procs);
  //
  //  if (mpi_err != 0) {
  //    printf("MPI initialization failed\n");
  //    exit(1);
  //  }

    // For testing a single process... should comment out when not testing.
  //  if (mpi_id + 1 != 5) {
  //    mpi_err = MPI_Finalize();
  //    return 1;
  //  }

  //  printf("Using %i out of %i processes.\n", mpi_id + 1, mpi_num_procs);
}

/**
 *
 */
void end_mpi() {
  // Wait until all other processes are completed before closing the manager
//  MPI_Status stat;
//  char message[10];
//  if (mpi_id > 0 ) {
//    // All non master processes should report done when completed.
//    sprintf(message, "Done");
//    MPI_Send(message, strlen(message)+1, MPI_BYTE, 0,1,MPI_COMM_WORLD);
//  }
//  else {
//    // The master process should wait to get 'Done' from each process
//    // before terminating
//    int proc;
//    for (proc = 1; proc < mpi_num_procs; proc++) {
//      MPI_Recv(message, sizeof(message), MPI_BYTE, proc, 1, MPI_COMM_WORLD, &stat);
//    }
//  }
//
//  // Terminate MPI.
//  mpi_err = MPI_Finalize();
}

<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
  Author: R. GUERNANE LPSC Grenoble CNRS/IN2P3
*/

#include "AliCaloRawAnalyzerFakeALTRO.h"
#include "AliCaloBunchInfo.h"
#include "AliCaloFitResults.h"
#include "AliLog.h"
#include "TMath.h"
#include <stdexcept>
#include <iostream>
#include "TF1.h"
#include "TGraph.h"
#include "AliCaloConstants.h"

using namespace std;

ClassImp( AliCaloRawAnalyzerFakeALTRO )

AliCaloRawAnalyzerFakeALTRO::AliCaloRawAnalyzerFakeALTRO() : AliCaloRawAnalyzerFitter("Chi Square Fit", "LMS")
{

}

AliCaloRawAnalyzerFakeALTRO::~AliCaloRawAnalyzerFakeALTRO()
{
  //delete fTf1;
}

AliCaloFitResults
AliCaloRawAnalyzerFakeALTRO::Evaluate( const vector<AliCaloBunchInfo>  &bunchvector, const UInt_t altrocfg1,  const UInt_t altrocfg2 )
{
  // Extracting signal parameters using fitting
  short maxampindex; //index of maximum amplitude
  short maxamp; //Maximum amplitude
  int index = SelectBunch( bunchvector,  &maxampindex,  &maxamp );

  if( index >= 0)
    {
      Float_t  ped  = ReverseAndSubtractPed( &(bunchvector.at(index))  ,  altrocfg1, altrocfg2, fReversed  );
      Float_t maxf = TMath::MaxElement( bunchvector.at(index).GetLength(),  fReversed );
      short maxrev = maxampindex  -  bunchvector.at(index).GetStartBin();
      // timebinOffset is timebin value at maximum (maxrev)
      short timebinOffset = maxampindex - (bunchvector.at(index).GetLength()-1);
      if(  maxf < fAmpCut  ||  ( maxamp - ped) > fOverflowCut  ) // (maxamp - ped) > fOverflowCut = Close to saturation (use low gain then)
	{
	  return  AliCaloFitResults( maxamp, ped, Ret::kCrude, maxf, timebinOffset);
 	}
      else if ( maxf >= fAmpCut )
	{
	  int first = 0;
	  int last = 0;
	  SelectSubarray( fReversed,  bunchvector.at(index).GetLength(),  maxrev, &first, &last, fFitArrayCut );
	  int nsamples =  last - first + 1;

	  if( ( nsamples  )  >= fNsampleCut )
	    {
	      Float_t tmax = (maxrev - first); // local tmax estimate
	      TGraph *graph =  new TGraph(  nsamples, fXaxis,  &fReversed[first] );
	      fTf1->SetParameter(0, maxf*fkEulerSquared );
	      fTf1->SetParameter(1, tmax - fTau);
	      // set rather loose parameter limits
	      fTf1->SetParLimits(0, 0.5*maxf*fkEulerSquared, 2*maxf*fkEulerSquared );
	      fTf1->SetParLimits(1, tmax - fTau - 4, tmax - fTau + 4);

	      if (fFixTau) {
		fTf1->FixParameter(2, fTau);
	      }
	      else {
		fTf1->ReleaseParameter(2); // allow par. to vary
		fTf1->SetParameter(2, fTau);
	      }

	      Short_t tmpStatus = 0;
	      try {
		tmpStatus =  graph->Fit(fTf1, "Q0RW");
	      }
	      catch (const std::exception & e) {
		AliError( Form("TGraph Fit exception %s", e.what()) );
		return AliCaloFitResults( maxamp, ped, Ret::kNoFit, maxf, timebinOffset,
					  timebinOffset, Ret::kDummy, Ret::kDummy,  Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );
	      }

	      if( fVerbose == true )
		{
		  AliCaloRawAnalyzer::PrintBunch( bunchvector.at(index) );
		  PrintFitResult( fTf1 ) ;
		}
	      // global tmax
	      tmax = fTf1->GetParameter(1) + timebinOffset - (maxrev - first) // abs. t0
		+ fTf1->GetParameter(2); // +tau, makes sum tmax

	        delete graph;
		return AliCaloFitResults( maxamp, ped , Ret::kFitPar,
					  fTf1->GetParameter(0)/fkEulerSquared,
					  tmax,
					  timebinOffset,
					  fTf1->GetChisquare(),
					  fTf1->GetNDF(),
					  Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );

		//     delete graph;

	    }
	  else
	    {
	      Float_t chi2 = CalculateChi2(maxf, maxrev, first, last);
	      Int_t ndf = last - first - 1; // nsamples - 2
	      return AliCaloFitResults( maxamp, ped, Ret::kCrude, maxf, timebinOffset,
					timebinOffset, chi2, ndf, Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );
	    }
        } // ampcut
    }
  return AliCaloFitResults(  Ret::kInvalid,  Ret::kInvalid );
}

<commit_msg>Bug fix: The fitting algorithm variable was not initialized for this class<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
  Author: R. GUERNANE LPSC Grenoble CNRS/IN2P3
*/

#include "AliCaloRawAnalyzerFakeALTRO.h"
#include "AliCaloBunchInfo.h"
#include "AliCaloFitResults.h"
#include "AliLog.h"
#include "TMath.h"
#include <stdexcept>
#include <iostream>
#include "TF1.h"
#include "TGraph.h"
#include "AliCaloConstants.h"

using namespace std;

ClassImp( AliCaloRawAnalyzerFakeALTRO )

AliCaloRawAnalyzerFakeALTRO::AliCaloRawAnalyzerFakeALTRO() : AliCaloRawAnalyzerFitter("Chi Square Fit", "LMS")
{
  fAlgo= Algo::kFakeAltro;
}

AliCaloRawAnalyzerFakeALTRO::~AliCaloRawAnalyzerFakeALTRO()
{
  //delete fTf1;
}

AliCaloFitResults
AliCaloRawAnalyzerFakeALTRO::Evaluate( const vector<AliCaloBunchInfo>  &bunchvector, const UInt_t altrocfg1,  const UInt_t altrocfg2 )
{
  // Extracting signal parameters using fitting
  short maxampindex; //index of maximum amplitude
  short maxamp; //Maximum amplitude
  int index = SelectBunch( bunchvector,  &maxampindex,  &maxamp );

  if( index >= 0)
    {
      Float_t  ped  = ReverseAndSubtractPed( &(bunchvector.at(index))  ,  altrocfg1, altrocfg2, fReversed  );
      Float_t maxf = TMath::MaxElement( bunchvector.at(index).GetLength(),  fReversed );
      short maxrev = maxampindex  -  bunchvector.at(index).GetStartBin();
      // timebinOffset is timebin value at maximum (maxrev)
      short timebinOffset = maxampindex - (bunchvector.at(index).GetLength()-1);
      if(  maxf < fAmpCut  ||  ( maxamp - ped) > fOverflowCut  ) // (maxamp - ped) > fOverflowCut = Close to saturation (use low gain then)
	{
	  return  AliCaloFitResults( maxamp, ped, Ret::kCrude, maxf, timebinOffset);
 	}
      else if ( maxf >= fAmpCut )
	{
	  int first = 0;
	  int last = 0;
	  SelectSubarray( fReversed,  bunchvector.at(index).GetLength(),  maxrev, &first, &last, fFitArrayCut );
	  int nsamples =  last - first + 1;

	  if( ( nsamples  )  >= fNsampleCut )
	    {
	      Float_t tmax = (maxrev - first); // local tmax estimate
	      TGraph *graph =  new TGraph(  nsamples, fXaxis,  &fReversed[first] );
	      fTf1->SetParameter(0, maxf*fkEulerSquared );
	      fTf1->SetParameter(1, tmax - fTau);
	      // set rather loose parameter limits
	      fTf1->SetParLimits(0, 0.5*maxf*fkEulerSquared, 2*maxf*fkEulerSquared );
	      fTf1->SetParLimits(1, tmax - fTau - 4, tmax - fTau + 4);

	      if (fFixTau) {
		fTf1->FixParameter(2, fTau);
	      }
	      else {
		fTf1->ReleaseParameter(2); // allow par. to vary
		fTf1->SetParameter(2, fTau);
	      }

	      Short_t tmpStatus = 0;
	      try {
		tmpStatus =  graph->Fit(fTf1, "Q0RW");
	      }
	      catch (const std::exception & e) {
		AliError( Form("TGraph Fit exception %s", e.what()) );
		return AliCaloFitResults( maxamp, ped, Ret::kNoFit, maxf, timebinOffset,
					  timebinOffset, Ret::kDummy, Ret::kDummy,  Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );
	      }

	      if( fVerbose == true )
		{
		  AliCaloRawAnalyzer::PrintBunch( bunchvector.at(index) );
		  PrintFitResult( fTf1 ) ;
		}
	      // global tmax
	      tmax = fTf1->GetParameter(1) + timebinOffset - (maxrev - first) // abs. t0
		+ fTf1->GetParameter(2); // +tau, makes sum tmax

	        delete graph;
		return AliCaloFitResults( maxamp, ped , Ret::kFitPar,
					  fTf1->GetParameter(0)/fkEulerSquared,
					  tmax,
					  timebinOffset,
					  fTf1->GetChisquare(),
					  fTf1->GetNDF(),
					  Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );

		//     delete graph;

	    }
	  else
	    {
	      Float_t chi2 = CalculateChi2(maxf, maxrev, first, last);
	      Int_t ndf = last - first - 1; // nsamples - 2
	      return AliCaloFitResults( maxamp, ped, Ret::kCrude, maxf, timebinOffset,
					timebinOffset, chi2, ndf, Ret::kDummy, AliCaloFitSubarray(index, maxrev, first, last) );
	    }
        } // ampcut
    }
  return AliCaloFitResults(  Ret::kInvalid,  Ret::kInvalid );
}

<|endoftext|>


<commit_before>/*
 * GStreamer
 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
 * Copyright (C) 2009 Andrey Nechypurenko <andreynech@gmail.com>
 * Copyright (C) 2010 Nuno Santos <nunosantos@imaginando.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <QtGui>
#include "gstthread.h"
#include "qglrenderer.h"
#include "pipeline.h"

#if defined(Q_WS_MAC)
extern void *qt_current_nsopengl_context();
#endif

QGLRenderer::QGLRenderer(const QString &videoLocation,
                         QWidget *parent)
  : QGLWidget(parent),
    videoLoc(videoLocation),
    gst_thread(NULL),
    closing(false),
    frame(NULL)
{
    move(20, 10);
    resize(640, 480);
}

QGLRenderer::~QGLRenderer()
{
}

void
QGLRenderer::initializeGL()
{
    GLContextID ctx;

#if defined(Q_WS_WIN)
    ctx.contextId = wglGetCurrentContext();
    ctx.dc = wglGetCurrentDC();
#elif defined (Q_WS_MAC)
    ctx.contextId = (NSOpenGLContext*) qt_current_nsopengl_context();
#elif defined(Q_WS_X11)
    ctx.contextId = glXGetCurrentContext();
    const char *display_name = getenv("DISPLAY");
    if(display_name == NULL)
    {
        // actually we should look for --display command line parameter here
        display_name = ":0.0";
    }
    ctx.display = XOpenDisplay(display_name);
    ctx.wnd = this->winId();
#endif

    // We need to unset Qt context before initializing gst-gl plugin.
    // Otherwise the attempt to share gst-gl context with Qt will fail.
    this->doneCurrent();
    this->gst_thread =
      new GstThread(ctx, this->videoLoc, SLOT(newFrame()), this);
    this->makeCurrent();

    QObject::connect(this->gst_thread, SIGNAL(finished()),
                   this, SLOT(close()));
    QObject::connect(this, SIGNAL(closeRequested()),
                   this->gst_thread, SLOT(stop()), Qt::QueuedConnection);

    qglClearColor(QApplication::palette().color(QPalette::Active,
                                                QPalette::Window));
    //glShadeModel(GL_FLAT);
    //glEnable(GL_DEPTH_TEST);
    //glEnable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_RECTANGLE_ARB); // Enable Texture Mapping

    this->gst_thread->start();
}

void
QGLRenderer::resizeGL(int width, int height)
{
  // Reset The Current Viewport And Perspective Transformation
  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
  glMatrixMode(GL_MODELVIEW);
}

void
QGLRenderer::newFrame()
{
    Pipeline *pipeline = this->gst_thread->getPipeline();
    if(!pipeline)
      return;

    /* frame is initialized as null */
    if (this->frame)
        pipeline->queue_output_buf.put(this->frame);

    this->frame = pipeline->queue_input_buf.get();

    /* direct call to paintGL (no queued) */
    this->updateGL();
}

void
QGLRenderer::paintGL()
{
    static GLfloat	xrot = 0;
    static GLfloat	yrot = 0;
    static GLfloat	zrot = 0;

    if (this->frame)
    {

        GLfloat width = this->frame->width;
        GLfloat height = this->frame->height;

        glEnable(GL_DEPTH_TEST);

        glEnable(GL_TEXTURE_RECTANGLE_ARB);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->frame->texture);
        if(glGetError () != GL_NO_ERROR)
        {
          qDebug ("failed to bind texture that comes from gst-gl");
          emit closeRequested();
          return;
        }

        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
                      GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
                      GL_CLAMP_TO_EDGE);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(0.0f,0.0f,-5.0f);

        glRotatef(xrot,1.0f,0.0f,0.0f);
        glRotatef(yrot,0.0f,1.0f,0.0f);
        glRotatef(zrot,0.0f,0.0f,1.0f);

        glBegin(GL_QUADS);
            // Front Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f,  1.0f);
            // Back Face
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            // Top Face
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            // Bottom Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(width,height); glVertex3f(-1.0f, -1.0f,  1.0f);
            // Right face
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, height); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            // Left Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f, -1.0f);
        glEnd();

        xrot+=0.3f;
        yrot+=0.2f;
        zrot+=0.4f;

        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    }
}

void
QGLRenderer::closeEvent(QCloseEvent* event)
{
    if(this->closing == false)
    {
        this->closing = true;
        emit closeRequested();
        event->ignore();
    }
}
<commit_msg>qglwtextureshare example: fix in qglrenderer.cpp<commit_after>/*
 * GStreamer
 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
 * Copyright (C) 2009 Andrey Nechypurenko <andreynech@gmail.com>
 * Copyright (C) 2010 Nuno Santos <nunosantos@imaginando.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <QtGui>
#include "gstthread.h"
#include "qglrenderer.h"
#include "pipeline.h"

#if defined(Q_WS_MAC)
extern void *qt_current_nsopengl_context();
#endif

/**
 * GluPerspective is part of the GLU library, and not supported as of newer (3.x?)
 * versions of OpenGL. An easy way to update the example is to write your own
 * replacement, something like this:
 *
 * See http://stackoverflow.com/questions/9210118/qts-opengl-samples-complain-about-some-errors-and-wont-run
 */
void gluPerspective(double fovy,double aspect, double zNear, double zFar)
{
     // Start in projection mode.
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     double xmin, xmax, ymin, ymax;
     ymax = zNear * tan(fovy * M_PI / 360.0);
     ymin = -ymax;
     xmin = ymin * aspect;
     xmax = ymax * aspect;
     glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}

QGLRenderer::QGLRenderer(const QString &videoLocation,
                         QWidget *parent)
  : QGLWidget(parent),
    videoLoc(videoLocation),
    gst_thread(NULL),
    closing(false),
    frame(NULL)
{
    move(20, 10);
    resize(640, 480);
}

QGLRenderer::~QGLRenderer()
{
}

void
QGLRenderer::initializeGL()
{
    GLContextID ctx;

#if defined(Q_WS_WIN)
    ctx.contextId = wglGetCurrentContext();
    ctx.dc = wglGetCurrentDC();
#elif defined (Q_WS_MAC)
    ctx.contextId = (NSOpenGLContext*) qt_current_nsopengl_context();
#elif defined(Q_WS_X11)
    ctx.contextId = glXGetCurrentContext();
    const char *display_name = getenv("DISPLAY");
    if(display_name == NULL)
    {
        // actually we should look for --display command line parameter here
        display_name = ":0.0";
    }
    ctx.display = XOpenDisplay(display_name);
    ctx.wnd = this->winId();
#endif

    // We need to unset Qt context before initializing gst-gl plugin.
    // Otherwise the attempt to share gst-gl context with Qt will fail.
    this->doneCurrent();
    this->gst_thread =
      new GstThread(ctx, this->videoLoc, SLOT(newFrame()), this);
    this->makeCurrent();

    QObject::connect(this->gst_thread, SIGNAL(finished()),
                   this, SLOT(close()));
    QObject::connect(this, SIGNAL(closeRequested()),
                   this->gst_thread, SLOT(stop()), Qt::QueuedConnection);

    qglClearColor(QApplication::palette().color(QPalette::Active,
                                                QPalette::Window));
    //glShadeModel(GL_FLAT);
    //glEnable(GL_DEPTH_TEST);
    //glEnable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_RECTANGLE_ARB); // Enable Texture Mapping

    this->gst_thread->start();
}

void
QGLRenderer::resizeGL(int width, int height)
{
  // Reset The Current Viewport And Perspective Transformation
  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
  glMatrixMode(GL_MODELVIEW);
}

void
QGLRenderer::newFrame()
{
    Pipeline *pipeline = this->gst_thread->getPipeline();
    if(!pipeline)
      return;

    /* frame is initialized as null */
    if (this->frame)
        pipeline->queue_output_buf.put(this->frame);

    this->frame = pipeline->queue_input_buf.get();

    /* direct call to paintGL (no queued) */
    this->updateGL();
}

void
QGLRenderer::paintGL()
{
    static GLfloat	xrot = 0;
    static GLfloat	yrot = 0;
    static GLfloat	zrot = 0;

    if (this->frame)
    {

        GLfloat width = this->frame->width;
        GLfloat height = this->frame->height;

        glEnable(GL_DEPTH_TEST);

        glEnable(GL_TEXTURE_RECTANGLE_ARB);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->frame->texture);
        if(glGetError () != GL_NO_ERROR)
        {
          qDebug ("failed to bind texture that comes from gst-gl");
          emit closeRequested();
          return;
        }

        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
                      GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
                      GL_CLAMP_TO_EDGE);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(0.0f,0.0f,-5.0f);

        glRotatef(xrot,1.0f,0.0f,0.0f);
        glRotatef(yrot,0.0f,1.0f,0.0f);
        glRotatef(zrot,0.0f,0.0f,1.0f);

        glBegin(GL_QUADS);
            // Front Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f,  1.0f);
            // Back Face
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            // Top Face
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            // Bottom Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(width,height); glVertex3f(-1.0f, -1.0f,  1.0f);
            // Right face
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, height); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(width, height); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            // Left Face
            glTexCoord2f(width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(0.0f, height); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(width, height); glVertex3f(-1.0f,  1.0f, -1.0f);
        glEnd();

        xrot+=0.3f;
        yrot+=0.2f;
        zrot+=0.4f;

        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    }
}

void
QGLRenderer::closeEvent(QCloseEvent* event)
{
    if(this->closing == false)
    {
        this->closing = true;
        emit closeRequested();
        event->ignore();
    }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <assert.h>

#include "cache.h"
#include "associative_cache.h"
#include "global_cached_private.h"
#include "part_global_cached_private.h"

int part_global_cached_private::thread_init() {
	/* let's bind the thread to a specific node first. */
	struct bitmask *nodemask = numa_allocate_cpumask();
	numa_bitmask_clearall(nodemask);
	printf("thread %d is associated to node %d\n", idx, get_group_id());
	numa_bitmask_setbit(nodemask, get_group_id());
	numa_bind(nodemask);
	numa_set_strict(1);
	numa_set_bind_policy(1);

	read_private::thread_init();
	request_queue = new bulk_queue<io_request>(REQ_QUEUE_SIZE);
	reply_queue = new bulk_queue<io_reply>(REPLY_QUEUE_SIZE);

	/*
	 * there is a global lock for all threads.
	 * so this lock makes sure cache initialization is serialized
	 */
	pthread_mutex_lock(&init_mutex);
	thread_group *group = &groups[group_idx];
	if (group->cache == NULL) {
		/* this allocates all pages for the cache. */
		page::allocate_cache(cache_size);
		group->cache = global_cached_private::create_cache(cache_type, cache_size, manager);
	}
	num_finish_init++;
	pthread_mutex_unlock(&init_mutex);

	pthread_mutex_lock(&wait_mutex);
	while (num_finish_init < nthreads) {
		pthread_cond_wait(&cond, &wait_mutex);
	}
	pthread_mutex_unlock(&wait_mutex);
	pthread_mutex_lock(&wait_mutex);
	pthread_cond_broadcast(&cond);
	pthread_mutex_unlock(&wait_mutex);
	printf("thread %d finishes initialization\n", idx);

	/*
	 * we have to initialize senders here
	 * because we need to make sure other threads have
	 * initialized all queues.
	 */
	/* there is a request sender for each node. */
	req_senders = (msg_sender<io_request> **) numa_alloc_local(
			sizeof(msg_sender<io_request> *) * num_groups);
	for (int i = 0; i < num_groups; i++) {
		bulk_queue<io_request> *queues[groups[i].nthreads];
		for (int j = 0; j < groups[i].nthreads; j++)
			queues[j] = groups[i].threads[j]->request_queue;
		req_senders[i] = new msg_sender<io_request>(BUF_SIZE, queues, groups[i].nthreads);
	}
	/*
	 * there is a reply sender for each thread.
	 * therefore, there is only one queue for a sender.
	 */
	reply_senders = (msg_sender<io_reply> **) numa_alloc_local(
			sizeof(msg_sender<io_reply> *) * nthreads);
	int idx = 0;
	for (int i = 0; i < num_groups; i++) {
		for (int j = 0; j < groups[i].nthreads; j++) {
			bulk_queue<io_reply> *queues[1];
			assert(idx == groups[i].threads[j]->idx);
			queues[0] = groups[i].threads[j]->reply_queue;
			reply_senders[idx++] = new msg_sender<io_reply>(BUF_SIZE, queues, 1);
		}
	}

	return 0;
}

part_global_cached_private::part_global_cached_private(int num_groups,
		const char *names[], int num, long size, int idx,
		long cache_size, int entry_size, int cache_type,
		memory_manager *manager): global_cached_private(names,
			num, size, idx, entry_size) {
	this->manager = manager;
	remote_reads = 0;
	//		assert(nthreads % num_groups == 0);
	this->num_groups = num_groups;
	this->group_idx = group_id(idx, num_groups);
	this->cache_size = cache_size / num_groups;
	this->cache_type = cache_type;
	processed_requests = 0;
	finished_threads = 0;
	req_senders = NULL;
	reply_senders = NULL;

	printf("cache is partitioned\n");
	printf("thread id: %d, group id: %d, num groups: %d\n", idx, group_idx, num_groups);

	if (groups == NULL) {
		pthread_mutex_init(&init_mutex, NULL);
		pthread_mutex_init(&wait_mutex, NULL);
		pthread_cond_init(&cond, NULL);
		num_finish_init = 0;
		groups = new thread_group[num_groups];
		for (int i = 0; i < num_groups; i++) {
			groups[i].id = i;
			groups[i].nthreads = nthreads / num_groups;
			if (nthreads % num_groups)
				groups[i].nthreads++;
			groups[i].threads = new part_global_cached_private*[groups[i].nthreads];
			groups[i].cache = NULL;
			for (int j = 0; j < groups[i].nthreads; j++)
				groups[i].threads[j] = NULL;
		}
	}

	/* assign a thread to a group. */
	thread_group *group = NULL;
	for (int i = 0; i < num_groups; i++) {
		if (groups[i].id == group_idx) {
			group = &groups[i];
			break;
		}
	}
	assert (group);
	int i = thread_idx(idx, num_groups);
	assert (group->threads[i] == NULL);
	group->threads[i] = this;
}

/**
 * send replies to the thread that sent the requests.
 */
int part_global_cached_private::reply(io_request *requests,
		io_reply *replies, int num) {
	for (int i = 0; i < num; i++) {
		part_global_cached_private *thread
			= (part_global_cached_private *) requests[i].get_thread();
		int thread_id = thread->idx;
		int num_sent = reply_senders[thread_id]->send_cached(&replies[i]);
		if (num_sent == 0) {
			// TODO the buffer is already full.
			// discard the request for now.
			printf("the reply buffer for thread %d is already full\n", thread_id);
			continue;
		}
	}
	for (int i = 0; i < nthreads; i++)
		reply_senders[i]->flush();
	return 0;
}

/* distribute requests to nodes. */
void part_global_cached_private::distribute_reqs(io_request *requests, int num) {
	for (int i = 0; i < num; i++) {
		int idx = hash_req(&requests[i]);
		assert (idx < num_groups);
		if (idx != get_group_id())
			remote_reads++;
		int num_sent = req_senders[idx]->send_cached(&requests[i]);
		// TODO if we fail to send the requests to the specific node,
		// we should rehash it and give it to another node.
		if (num_sent == 0) {
			// TODO the buffer is already full.
			// discard the request for now.
			printf("the request buffer for group %d is already full\n", idx);
			continue;
		}
	}
	for (int i = 0; i < num_groups; i++)
		req_senders[i]->flush();
}

/* process the requests sent to this thread */
int part_global_cached_private::process_requests(int max_nreqs) {
	int num_processed = 0;
	io_request local_reqs[BUF_SIZE];
	io_reply local_replies[BUF_SIZE];
	while (!request_queue->is_empty() && num_processed < max_nreqs) {
		int num = request_queue->fetch(local_reqs, BUF_SIZE);
		for (int i = 0; i < num; i++) {
			io_request *req = &local_reqs[i];
			// TODO will it be better if I collect all data
			// and send them back to the initiator in blocks?
			int access_method = req->get_access_method();
			assert(req->get_offset() >= 0);
			int ret = global_cached_private::access(req->get_buf(),
					req->get_offset(), req->get_size(), access_method);
			local_replies[i] = io_reply(req, ret >= 0, errno);
		}
		num_processed += num;
		reply(local_reqs, local_replies, num);
	}
	processed_requests += num_processed;
	return num_processed;
}

/*
 * process the replies and return the number
 * of bytes that have been accessed.
 */
int part_global_cached_private::process_replies(int max_nreplies) {
	int num_processed = 0;
	io_reply local_replies[BUF_SIZE];
	int size = 0;
	while(!reply_queue->is_empty() && num_processed < max_nreplies) {
		int num = reply_queue->fetch(local_replies, BUF_SIZE);
		for (int i = 0; i < num; i++) {
			io_reply *reply = &local_replies[i];
			int ret = process_reply(reply);
			if (ret >= 0)
				size += ret;
		}
		num_processed += num;
	}
	return num_processed;
}

int part_global_cached_private::process_reply(io_reply *reply) {
	extern bool verify_read_content;
	int access_method = reply->get_access_method();
	int ret = -1;
	if (reply->is_success()) {
		read_bytes += reply->get_size();
		if (access_method == READ && verify_read_content) {
			assert(*(unsigned long *) reply->get_buf()
					== reply->get_offset() / sizeof(long));
		}
		ret = reply->get_size();
		buf->free_entry(reply->get_buf());
	}
	else {
		fprintf(stderr, "access error: %s\n",
				strerror(reply->get_status()));
	}
	return ret;
}

ssize_t part_global_cached_private::access(io_request *requests,
		int num, int access_method) {
	distribute_reqs(requests, num);
	/*
	 * let's process up to twice as many requests as demanded by the upper layer,
	 * I hope this can help load balancing problem.
	 */
	int num_recv = 0;
	/* we need to process them at least once. */
	process_requests(num * 2);
	num_recv += process_replies(num * 4);
	while (buf->is_full()) {
		process_requests(num * 2);
		num_recv += process_replies(num * 4);
	}
	return num_recv;
}

void part_global_cached_private::cleanup() {
	int num = 0;
	printf("thread %d: start to clean up\n", idx);
	for (int i = 0; i < num_groups; i++) {
		for (int j = 0; j < groups[i].nthreads; j++)
			if (groups[i].threads[j])
				__sync_fetch_and_add(&groups[i].threads[j]->finished_threads, 1);
	}
	while (!request_queue->is_empty()
			|| !reply_queue->is_empty()
			/*
			 * if finished_threads == nthreads,
			 * then all threads have reached the point.
			 */
			|| finished_threads < nthreads) {
		process_requests(200);
		process_replies(200);
		num++;
	}
	printf("thread %d processed %ld requests\n", idx, processed_requests);
}

thread_group *part_global_cached_private::groups;
pthread_mutex_t part_global_cached_private::init_mutex;
int part_global_cached_private::num_finish_init;
pthread_mutex_t part_global_cached_private::wait_mutex;
pthread_cond_t part_global_cached_private::cond;
<commit_msg>bind threads to nodes only when NUM_NODES > 1<commit_after>#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <assert.h>

#include "cache.h"
#include "associative_cache.h"
#include "global_cached_private.h"
#include "part_global_cached_private.h"

int part_global_cached_private::thread_init() {
#if NUM_NODES > 1
	/* let's bind the thread to a specific node first. */
	struct bitmask *nodemask = numa_allocate_cpumask();
	numa_bitmask_clearall(nodemask);
	printf("thread %d is associated to node %d\n", idx, get_group_id());
	numa_bitmask_setbit(nodemask, get_group_id());
	numa_bind(nodemask);
	numa_set_strict(1);
	numa_set_bind_policy(1);
#endif

	read_private::thread_init();
	request_queue = new bulk_queue<io_request>(REQ_QUEUE_SIZE);
	reply_queue = new bulk_queue<io_reply>(REPLY_QUEUE_SIZE);

	/*
	 * there is a global lock for all threads.
	 * so this lock makes sure cache initialization is serialized
	 */
	pthread_mutex_lock(&init_mutex);
	thread_group *group = &groups[group_idx];
	if (group->cache == NULL) {
		/* this allocates all pages for the cache. */
		page::allocate_cache(cache_size);
		group->cache = global_cached_private::create_cache(cache_type, cache_size, manager);
	}
	num_finish_init++;
	pthread_mutex_unlock(&init_mutex);

	pthread_mutex_lock(&wait_mutex);
	while (num_finish_init < nthreads) {
		pthread_cond_wait(&cond, &wait_mutex);
	}
	pthread_mutex_unlock(&wait_mutex);
	pthread_mutex_lock(&wait_mutex);
	pthread_cond_broadcast(&cond);
	pthread_mutex_unlock(&wait_mutex);
	printf("thread %d finishes initialization\n", idx);

	/*
	 * we have to initialize senders here
	 * because we need to make sure other threads have
	 * initialized all queues.
	 */
	/* there is a request sender for each node. */
	req_senders = (msg_sender<io_request> **) numa_alloc_local(
			sizeof(msg_sender<io_request> *) * num_groups);
	for (int i = 0; i < num_groups; i++) {
		bulk_queue<io_request> *queues[groups[i].nthreads];
		for (int j = 0; j < groups[i].nthreads; j++)
			queues[j] = groups[i].threads[j]->request_queue;
		req_senders[i] = new msg_sender<io_request>(BUF_SIZE, queues, groups[i].nthreads);
	}
	/*
	 * there is a reply sender for each thread.
	 * therefore, there is only one queue for a sender.
	 */
	reply_senders = (msg_sender<io_reply> **) numa_alloc_local(
			sizeof(msg_sender<io_reply> *) * nthreads);
	int idx = 0;
	for (int i = 0; i < num_groups; i++) {
		for (int j = 0; j < groups[i].nthreads; j++) {
			bulk_queue<io_reply> *queues[1];
			assert(idx == groups[i].threads[j]->idx);
			queues[0] = groups[i].threads[j]->reply_queue;
			reply_senders[idx++] = new msg_sender<io_reply>(BUF_SIZE, queues, 1);
		}
	}

	return 0;
}

part_global_cached_private::part_global_cached_private(int num_groups,
		const char *names[], int num, long size, int idx,
		long cache_size, int entry_size, int cache_type,
		memory_manager *manager): global_cached_private(names,
			num, size, idx, entry_size) {
	this->manager = manager;
	remote_reads = 0;
	//		assert(nthreads % num_groups == 0);
	this->num_groups = num_groups;
	this->group_idx = group_id(idx, num_groups);
	this->cache_size = cache_size / num_groups;
	this->cache_type = cache_type;
	processed_requests = 0;
	finished_threads = 0;
	req_senders = NULL;
	reply_senders = NULL;

	printf("cache is partitioned\n");
	printf("thread id: %d, group id: %d, num groups: %d\n", idx, group_idx, num_groups);

	if (groups == NULL) {
		pthread_mutex_init(&init_mutex, NULL);
		pthread_mutex_init(&wait_mutex, NULL);
		pthread_cond_init(&cond, NULL);
		num_finish_init = 0;
		groups = new thread_group[num_groups];
		for (int i = 0; i < num_groups; i++) {
			groups[i].id = i;
			groups[i].nthreads = nthreads / num_groups;
			if (nthreads % num_groups)
				groups[i].nthreads++;
			groups[i].threads = new part_global_cached_private*[groups[i].nthreads];
			groups[i].cache = NULL;
			for (int j = 0; j < groups[i].nthreads; j++)
				groups[i].threads[j] = NULL;
		}
	}

	/* assign a thread to a group. */
	thread_group *group = NULL;
	for (int i = 0; i < num_groups; i++) {
		if (groups[i].id == group_idx) {
			group = &groups[i];
			break;
		}
	}
	assert (group);
	int i = thread_idx(idx, num_groups);
	assert (group->threads[i] == NULL);
	group->threads[i] = this;
}

/**
 * send replies to the thread that sent the requests.
 */
int part_global_cached_private::reply(io_request *requests,
		io_reply *replies, int num) {
	for (int i = 0; i < num; i++) {
		part_global_cached_private *thread
			= (part_global_cached_private *) requests[i].get_thread();
		int thread_id = thread->idx;
		int num_sent = reply_senders[thread_id]->send_cached(&replies[i]);
		if (num_sent == 0) {
			// TODO the buffer is already full.
			// discard the request for now.
			printf("the reply buffer for thread %d is already full\n", thread_id);
			continue;
		}
	}
	for (int i = 0; i < nthreads; i++)
		reply_senders[i]->flush();
	return 0;
}

/* distribute requests to nodes. */
void part_global_cached_private::distribute_reqs(io_request *requests, int num) {
	for (int i = 0; i < num; i++) {
		int idx = hash_req(&requests[i]);
		assert (idx < num_groups);
		if (idx != get_group_id())
			remote_reads++;
		int num_sent = req_senders[idx]->send_cached(&requests[i]);
		// TODO if we fail to send the requests to the specific node,
		// we should rehash it and give it to another node.
		if (num_sent == 0) {
			// TODO the buffer is already full.
			// discard the request for now.
			printf("the request buffer for group %d is already full\n", idx);
			continue;
		}
	}
	for (int i = 0; i < num_groups; i++)
		req_senders[i]->flush();
}

/* process the requests sent to this thread */
int part_global_cached_private::process_requests(int max_nreqs) {
	int num_processed = 0;
	io_request local_reqs[BUF_SIZE];
	io_reply local_replies[BUF_SIZE];
	while (!request_queue->is_empty() && num_processed < max_nreqs) {
		int num = request_queue->fetch(local_reqs, BUF_SIZE);
		for (int i = 0; i < num; i++) {
			io_request *req = &local_reqs[i];
			// TODO will it be better if I collect all data
			// and send them back to the initiator in blocks?
			int access_method = req->get_access_method();
			assert(req->get_offset() >= 0);
			int ret = global_cached_private::access(req->get_buf(),
					req->get_offset(), req->get_size(), access_method);
			local_replies[i] = io_reply(req, ret >= 0, errno);
		}
		num_processed += num;
		reply(local_reqs, local_replies, num);
	}
	processed_requests += num_processed;
	return num_processed;
}

/*
 * process the replies and return the number
 * of bytes that have been accessed.
 */
int part_global_cached_private::process_replies(int max_nreplies) {
	int num_processed = 0;
	io_reply local_replies[BUF_SIZE];
	int size = 0;
	while(!reply_queue->is_empty() && num_processed < max_nreplies) {
		int num = reply_queue->fetch(local_replies, BUF_SIZE);
		for (int i = 0; i < num; i++) {
			io_reply *reply = &local_replies[i];
			int ret = process_reply(reply);
			if (ret >= 0)
				size += ret;
		}
		num_processed += num;
	}
	return num_processed;
}

int part_global_cached_private::process_reply(io_reply *reply) {
	extern bool verify_read_content;
	int access_method = reply->get_access_method();
	int ret = -1;
	if (reply->is_success()) {
		read_bytes += reply->get_size();
		if (access_method == READ && verify_read_content) {
			assert(*(unsigned long *) reply->get_buf()
					== reply->get_offset() / sizeof(long));
		}
		ret = reply->get_size();
		buf->free_entry(reply->get_buf());
	}
	else {
		fprintf(stderr, "access error: %s\n",
				strerror(reply->get_status()));
	}
	return ret;
}

ssize_t part_global_cached_private::access(io_request *requests,
		int num, int access_method) {
	distribute_reqs(requests, num);
	/*
	 * let's process up to twice as many requests as demanded by the upper layer,
	 * I hope this can help load balancing problem.
	 */
	int num_recv = 0;
	/* we need to process them at least once. */
	process_requests(num * 2);
	num_recv += process_replies(num * 4);
	while (buf->is_full()) {
		process_requests(num * 2);
		num_recv += process_replies(num * 4);
	}
	return num_recv;
}

void part_global_cached_private::cleanup() {
	int num = 0;
	printf("thread %d: start to clean up\n", idx);
	for (int i = 0; i < num_groups; i++) {
		for (int j = 0; j < groups[i].nthreads; j++)
			if (groups[i].threads[j])
				__sync_fetch_and_add(&groups[i].threads[j]->finished_threads, 1);
	}
	while (!request_queue->is_empty()
			|| !reply_queue->is_empty()
			/*
			 * if finished_threads == nthreads,
			 * then all threads have reached the point.
			 */
			|| finished_threads < nthreads) {
		process_requests(200);
		process_replies(200);
		num++;
	}
	printf("thread %d processed %ld requests\n", idx, processed_requests);
}

thread_group *part_global_cached_private::groups;
pthread_mutex_t part_global_cached_private::init_mutex;
int part_global_cached_private::num_finish_init;
pthread_mutex_t part_global_cached_private::wait_mutex;
pthread_cond_t part_global_cached_private::cond;
<|endoftext|>


<commit_before>//===-- sanitizer_posix.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements POSIX-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_MAC

#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"

#include <sys/mman.h>
#include <signal.h>

namespace __sanitizer {

// ------------- sanitizer_common.h
uptr GetMmapGranularity() {
  return GetPageSize();
}

uptr GetMaxVirtualAddress() {
#if SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__)
  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
  // We somehow need to figure our which one we are using now and choose
  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
  // of the address space, so simply checking the stack address is not enough.
  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
# else
  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
# endif
#else  // SANITIZER_WORDSIZE == 32
  // FIXME: We can probably lower this on Android?
  return (1ULL << 32) - 1;  // 0xffffffff;
#endif  // SANITIZER_WORDSIZE
}

void *MmapOrDie(uptr size, const char *mem_type) {
  size = RoundUpTo(size, GetPageSizeCached());
  uptr res = internal_mmap(0, size,
                            PROT_READ | PROT_WRITE,
                            MAP_PRIVATE | MAP_ANON, -1, 0);
  int reserrno;
  if (internal_iserror(res, &reserrno)) {
    static int recursion_count;
    if (recursion_count) {
      // The Report() and CHECK calls below may call mmap recursively and fail.
      // If we went into recursion, just die.
      RawWrite("ERROR: Failed to mmap\n");
      Die();
    }
    recursion_count++;
    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
           SanitizerToolName, size, size, mem_type, reserrno);
    DumpProcessMap();
    CHECK("unable to mmap" && 0);
  }
  return (void *)res;
}

void UnmapOrDie(void *addr, uptr size) {
  if (!addr || !size) return;
  uptr res = internal_munmap(addr, size);
  if (internal_iserror(res)) {
    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
           SanitizerToolName, size, size, addr);
    CHECK("unable to unmap" && 0);
  }
}

void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap(0,
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno)) {
    Report("ERROR: "
           "%s failed to allocate noreserve 0x%zx (%zd) bytes for '%s' (%d)\n",
           SanitizerToolName, size, size, mem_type, reserrno);
    CHECK("unable to mmap" && 0);
  }
  return (void *)p;
}

void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno))
    Report("ERROR: "
           "%s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
           SanitizerToolName, size, size, fixed_addr, reserrno);
  return (void *)p;
}

void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno)) {
    Report("ERROR:"
           " %s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
           SanitizerToolName, size, size, fixed_addr, reserrno);
    CHECK("unable to mmap" && 0);
  }
  return (void *)p;
}

void *Mprotect(uptr fixed_addr, uptr size) {
  return (void *)internal_mmap((void*)fixed_addr, size,
                               PROT_NONE,
                               MAP_PRIVATE | MAP_ANON | MAP_FIXED |
                               MAP_NORESERVE, -1, 0);
}

void *MapFileToMemory(const char *file_name, uptr *buff_size) {
  uptr openrv = OpenFile(file_name, false);
  CHECK(!internal_iserror(openrv));
  fd_t fd = openrv;
  uptr fsize = internal_filesize(fd);
  CHECK_NE(fsize, (uptr)-1);
  CHECK_GT(fsize, 0);
  *buff_size = RoundUpTo(fsize, GetPageSizeCached());
  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
  return internal_iserror(map) ? 0 : (void *)map;
}

static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
                                        uptr start2, uptr end2) {
  CHECK(start1 <= end1);
  CHECK(start2 <= end2);
  return (end1 < start2) || (end2 < start1);
}

// FIXME: this is thread-unsafe, but should not cause problems most of the time.
// When the shadow is mapped only a single thread usually exists (plus maybe
// several worker threads on Mac, which aren't expected to map big chunks of
// memory).
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end;
  while (proc_maps.Next(&start, &end,
                        /*offset*/0, /*filename*/0, /*filename_size*/0,
                        /*protection*/0)) {
    if (!IntervalsAreSeparate(start, end, range_start, range_end))
      return false;
  }
  return true;
}

void DumpProcessMap() {
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end;
  const sptr kBufSize = 4095;
  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
  Report("Process memory map follows:\n");
  while (proc_maps.Next(&start, &end, /* file_offset */0,
                        filename, kBufSize, /* protection */0)) {
    Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
  }
  Report("End of process memory map.\n");
  UnmapOrDie(filename, kBufSize);
}

const char *GetPwd() {
  return GetEnv("PWD");
}

char *FindPathToBinary(const char *name) {
  const char *path = GetEnv("PATH");
  if (!path)
    return 0;
  uptr name_len = internal_strlen(name);
  InternalScopedBuffer<char> buffer(kMaxPathLength);
  const char *beg = path;
  while (true) {
    const char *end = internal_strchrnul(beg, ':');
    uptr prefix_len = end - beg;
    if (prefix_len + name_len + 2 <= kMaxPathLength) {
      internal_memcpy(buffer.data(), beg, prefix_len);
      buffer[prefix_len] = '/';
      internal_memcpy(&buffer[prefix_len + 1], name, name_len);
      buffer[prefix_len + 1 + name_len] = '\0';
      if (FileExists(buffer.data()))
        return internal_strdup(buffer.data());
    }
    if (*end == '\0') break;
    beg = end + 1;
  }
  return 0;
}

void MaybeOpenReportFile() {
  if (!log_to_file) return;
  uptr pid = internal_getpid();
  // If in tracer, use the parent's file.
  if (pid == stoptheworld_tracer_pid)
    pid = stoptheworld_tracer_ppid;
  if (report_fd_pid == pid) return;
  InternalScopedBuffer<char> report_path_full(4096);
  internal_snprintf(report_path_full.data(), report_path_full.size(),
                    "%s.%zu", report_path_prefix, pid);
  uptr openrv = OpenFile(report_path_full.data(), true);
  if (internal_iserror(openrv)) {
    report_fd = kStderrFd;
    log_to_file = false;
    Report("ERROR: Can't open file: %s\n", report_path_full.data());
    Die();
  }
  if (report_fd != kInvalidFd) {
    // We're in the child. Close the parent's log.
    internal_close(report_fd);
  }
  report_fd = openrv;
  report_fd_pid = pid;
}

void RawWrite(const char *buffer) {
  static const char *kRawWriteError =
      "RawWrite can't output requested buffer!\n";
  uptr length = (uptr)internal_strlen(buffer);
  MaybeOpenReportFile();
  if (length != internal_write(report_fd, buffer, length)) {
    internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
    Die();
  }
}

bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
  uptr s, e, off, prot;
  InternalScopedString buff(4096);
  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
  while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
    if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
        && internal_strcmp(module, buff.data()) == 0) {
      *start = s;
      *end = e;
      return true;
    }
  }
  return false;
}

}  // namespace __sanitizer

#endif  // SANITIZER_LINUX || SANITIZER_MAC
<commit_msg>[ASan] Remove an accidentally added include of signal.h<commit_after>//===-- sanitizer_posix.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements POSIX-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_MAC

#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"

#include <sys/mman.h>

namespace __sanitizer {

// ------------- sanitizer_common.h
uptr GetMmapGranularity() {
  return GetPageSize();
}

uptr GetMaxVirtualAddress() {
#if SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__)
  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
  // We somehow need to figure our which one we are using now and choose
  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
  // of the address space, so simply checking the stack address is not enough.
  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
# else
  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
# endif
#else  // SANITIZER_WORDSIZE == 32
  // FIXME: We can probably lower this on Android?
  return (1ULL << 32) - 1;  // 0xffffffff;
#endif  // SANITIZER_WORDSIZE
}

void *MmapOrDie(uptr size, const char *mem_type) {
  size = RoundUpTo(size, GetPageSizeCached());
  uptr res = internal_mmap(0, size,
                            PROT_READ | PROT_WRITE,
                            MAP_PRIVATE | MAP_ANON, -1, 0);
  int reserrno;
  if (internal_iserror(res, &reserrno)) {
    static int recursion_count;
    if (recursion_count) {
      // The Report() and CHECK calls below may call mmap recursively and fail.
      // If we went into recursion, just die.
      RawWrite("ERROR: Failed to mmap\n");
      Die();
    }
    recursion_count++;
    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
           SanitizerToolName, size, size, mem_type, reserrno);
    DumpProcessMap();
    CHECK("unable to mmap" && 0);
  }
  return (void *)res;
}

void UnmapOrDie(void *addr, uptr size) {
  if (!addr || !size) return;
  uptr res = internal_munmap(addr, size);
  if (internal_iserror(res)) {
    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
           SanitizerToolName, size, size, addr);
    CHECK("unable to unmap" && 0);
  }
}

void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap(0,
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno)) {
    Report("ERROR: "
           "%s failed to allocate noreserve 0x%zx (%zd) bytes for '%s' (%d)\n",
           SanitizerToolName, size, size, mem_type, reserrno);
    CHECK("unable to mmap" && 0);
  }
  return (void *)p;
}

void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno))
    Report("ERROR: "
           "%s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
           SanitizerToolName, size, size, fixed_addr, reserrno);
  return (void *)p;
}

void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
  uptr PageSize = GetPageSizeCached();
  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
      RoundUpTo(size, PageSize),
      PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
      -1, 0);
  int reserrno;
  if (internal_iserror(p, &reserrno)) {
    Report("ERROR:"
           " %s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
           SanitizerToolName, size, size, fixed_addr, reserrno);
    CHECK("unable to mmap" && 0);
  }
  return (void *)p;
}

void *Mprotect(uptr fixed_addr, uptr size) {
  return (void *)internal_mmap((void*)fixed_addr, size,
                               PROT_NONE,
                               MAP_PRIVATE | MAP_ANON | MAP_FIXED |
                               MAP_NORESERVE, -1, 0);
}

void *MapFileToMemory(const char *file_name, uptr *buff_size) {
  uptr openrv = OpenFile(file_name, false);
  CHECK(!internal_iserror(openrv));
  fd_t fd = openrv;
  uptr fsize = internal_filesize(fd);
  CHECK_NE(fsize, (uptr)-1);
  CHECK_GT(fsize, 0);
  *buff_size = RoundUpTo(fsize, GetPageSizeCached());
  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
  return internal_iserror(map) ? 0 : (void *)map;
}

static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
                                        uptr start2, uptr end2) {
  CHECK(start1 <= end1);
  CHECK(start2 <= end2);
  return (end1 < start2) || (end2 < start1);
}

// FIXME: this is thread-unsafe, but should not cause problems most of the time.
// When the shadow is mapped only a single thread usually exists (plus maybe
// several worker threads on Mac, which aren't expected to map big chunks of
// memory).
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end;
  while (proc_maps.Next(&start, &end,
                        /*offset*/0, /*filename*/0, /*filename_size*/0,
                        /*protection*/0)) {
    if (!IntervalsAreSeparate(start, end, range_start, range_end))
      return false;
  }
  return true;
}

void DumpProcessMap() {
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end;
  const sptr kBufSize = 4095;
  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
  Report("Process memory map follows:\n");
  while (proc_maps.Next(&start, &end, /* file_offset */0,
                        filename, kBufSize, /* protection */0)) {
    Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
  }
  Report("End of process memory map.\n");
  UnmapOrDie(filename, kBufSize);
}

const char *GetPwd() {
  return GetEnv("PWD");
}

char *FindPathToBinary(const char *name) {
  const char *path = GetEnv("PATH");
  if (!path)
    return 0;
  uptr name_len = internal_strlen(name);
  InternalScopedBuffer<char> buffer(kMaxPathLength);
  const char *beg = path;
  while (true) {
    const char *end = internal_strchrnul(beg, ':');
    uptr prefix_len = end - beg;
    if (prefix_len + name_len + 2 <= kMaxPathLength) {
      internal_memcpy(buffer.data(), beg, prefix_len);
      buffer[prefix_len] = '/';
      internal_memcpy(&buffer[prefix_len + 1], name, name_len);
      buffer[prefix_len + 1 + name_len] = '\0';
      if (FileExists(buffer.data()))
        return internal_strdup(buffer.data());
    }
    if (*end == '\0') break;
    beg = end + 1;
  }
  return 0;
}

void MaybeOpenReportFile() {
  if (!log_to_file) return;
  uptr pid = internal_getpid();
  // If in tracer, use the parent's file.
  if (pid == stoptheworld_tracer_pid)
    pid = stoptheworld_tracer_ppid;
  if (report_fd_pid == pid) return;
  InternalScopedBuffer<char> report_path_full(4096);
  internal_snprintf(report_path_full.data(), report_path_full.size(),
                    "%s.%zu", report_path_prefix, pid);
  uptr openrv = OpenFile(report_path_full.data(), true);
  if (internal_iserror(openrv)) {
    report_fd = kStderrFd;
    log_to_file = false;
    Report("ERROR: Can't open file: %s\n", report_path_full.data());
    Die();
  }
  if (report_fd != kInvalidFd) {
    // We're in the child. Close the parent's log.
    internal_close(report_fd);
  }
  report_fd = openrv;
  report_fd_pid = pid;
}

void RawWrite(const char *buffer) {
  static const char *kRawWriteError =
      "RawWrite can't output requested buffer!\n";
  uptr length = (uptr)internal_strlen(buffer);
  MaybeOpenReportFile();
  if (length != internal_write(report_fd, buffer, length)) {
    internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
    Die();
  }
}

bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
  uptr s, e, off, prot;
  InternalScopedString buff(4096);
  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
  while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
    if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
        && internal_strcmp(module, buff.data()) == 0) {
      *start = s;
      *end = e;
      return true;
    }
  }
  return false;
}

}  // namespace __sanitizer

#endif  // SANITIZER_LINUX || SANITIZER_MAC
<|endoftext|>


<commit_before>//DEFINITION OF A FEW CONSTANTS

AliPWG4HighPtQAMC* AddTaskPWG4HighPtQAMC()
{
  // Creates HighPtQAMC analysis task and adds it to the analysis manager.

  // A. Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTaskPWG4HighPtQMC", "No analysis manager to connect to.");
    return NULL;
  }

  // B. Check the analysis type using the event handlers connected to the analysis
  //    manager. The availability of MC handler can also be checked here.
  //==============================================================================
  if (!mgr->GetInputEventHandler()) {
    ::Error("AddPWG4TaskHighPtQAMC", "This task requires an input event handler");
    return NULL;
  }
  TString type = mgr->GetInputEventHandler()->GetDataType(); // can be "ESD" or "AOD"
  const char *analysisType = "ESD";//"TPC"

  // C. Create the task, add it to manager.
  //===========================================================================

  //CREATE THE  CUTS -----------------------------------------------
  //Use AliESDtrackCuts
  AliESDtrackCuts *trackCuts = new AliESDtrackCuts("AliESDtrackCuts","Standard Cuts");
  //Standard Cuts
  trackCuts=trackCuts->GetStandardITSTPCTrackCuts2009(kTRUE);//Primary Track Selection
  trackCuts->SetEtaRange(-0.9,0.9);
  trackCuts->SetPtRange(0.15, 1e10);
  trackCuts->SetRequireITSRefit(kFALSE);

  AliESDtrackCuts *trackCutsITS = new AliESDtrackCuts("AliESDtrackCuts","Standard Cuts with ITSrefit");
  //Standard Cuts
  trackCuts=trackCuts->GetStandardITSTPCTrackCuts2009(kTRUE);//Primary Track Selection
  trackCuts->SetEtaRange(-0.9,0.9);
  trackCuts->SetPtRange(0.15, 1e10);
  trackCuts->SetRequireITSRefit(kTRUE);

  //Create the task
  AliPWG4HighPtQAMC *taskPWG4QAMC = new AliPWG4HighPtQAMC("AliPWG4HighPtQAMC");
  taskPWG4QAMC->SetCuts(trackCuts);
  taskPWG4QAMC->SetCutsITS(trackCutsITS);

  // E. Create ONLY the output containers for the data produced by the task.
  // Get and connect other common input/output containers via the manager as below
  //==============================================================================

  //------ input data ------
  //  AliAnalysisDataContainer *cinput0  = mgr->GetCommonInputContainer();
  printf("Create output containers \n");
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG4_HighPtQAMC";
  //char *outputfile = "outputAliPWG4HighPtQAMCTestTrain.root";
  AliAnalysisDataContainer *cout_hist0 = mgr->CreateContainer("qa_histsMC", TList::Class(), AliAnalysisManager::kOutputContainer,outputfile);
  AliAnalysisDataContainer *cout_hist2 = mgr->CreateContainer("qa_histsMCITS", TList::Class(), AliAnalysisManager::kOutputContainer,outputfile);

  mgr->AddTask(taskPWG4QAMC);
  mgr->ConnectInput(taskPWG4QAMC,0,mgr->GetCommonInputContainer());
  mgr->ConnectOutput(taskPWG4QAMC,0,cout_hist0);
  mgr->ConnectOutput(taskPWG4QAMC,1,cout_hist2);

  // Return task pointer at the end
  return taskPWG4QAMC;
}
<commit_msg>bug fix in definition of track cuts (Marta)<commit_after>//DEFINITION OF A FEW CONSTANTS

AliPWG4HighPtQAMC* AddTaskPWG4HighPtQAMC()
{
  // Creates HighPtQAMC analysis task and adds it to the analysis manager.

  // A. Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTaskPWG4HighPtQMC", "No analysis manager to connect to.");
    return NULL;
  }

  // B. Check the analysis type using the event handlers connected to the analysis
  //    manager. The availability of MC handler can also be checked here.
  //==============================================================================
  if (!mgr->GetInputEventHandler()) {
    ::Error("AddPWG4TaskHighPtQAMC", "This task requires an input event handler");
    return NULL;
  }
  TString type = mgr->GetInputEventHandler()->GetDataType(); // can be "ESD" or "AOD"
  const char *analysisType = "ESD";//"TPC"

  // C. Create the task, add it to manager.
  //===========================================================================

  //CREATE THE  CUTS -----------------------------------------------
  //Use AliESDtrackCuts
  AliESDtrackCuts *trackCuts = new AliESDtrackCuts("AliESDtrackCuts","Standard Cuts");
  //Standard Cuts
  trackCuts=trackCuts->GetStandardITSTPCTrackCuts2009(kTRUE);//Primary Track Selection
  trackCuts->SetEtaRange(-0.9,0.9);
  trackCuts->SetPtRange(0.15, 1e10);
  trackCuts->SetRequireITSRefit(kFALSE);

  AliESDtrackCuts *trackCutsITS = new AliESDtrackCuts("AliESDtrackCuts","Standard Cuts with ITSrefit");
  //Standard Cuts
  trackCutsITS=trackCuts->GetStandardITSTPCTrackCuts2009(kTRUE);//Primary Track Selection
  trackCutsITS->SetEtaRange(-0.9,0.9);
  trackCutsITS->SetPtRange(0.15, 1e10);
  trackCutsITS->SetRequireITSRefit(kTRUE);

  //Create the task
  AliPWG4HighPtQAMC *taskPWG4QAMC = new AliPWG4HighPtQAMC("AliPWG4HighPtQAMC");
  taskPWG4QAMC->SetCuts(trackCuts);
  taskPWG4QAMC->SetCutsITS(trackCutsITS);

  // E. Create ONLY the output containers for the data produced by the task.
  // Get and connect other common input/output containers via the manager as below
  //==============================================================================

  //------ input data ------
  //  AliAnalysisDataContainer *cinput0  = mgr->GetCommonInputContainer();
  printf("Create output containers \n");
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG4_HighPtQAMC";
  //char *outputfile = "outputAliPWG4HighPtQAMCTestTrain.root";
  AliAnalysisDataContainer *cout_hist0 = mgr->CreateContainer("qa_histsMC", TList::Class(), AliAnalysisManager::kOutputContainer,outputfile);
  AliAnalysisDataContainer *cout_hist2 = mgr->CreateContainer("qa_histsMCITS", TList::Class(), AliAnalysisManager::kOutputContainer,outputfile);

  mgr->AddTask(taskPWG4QAMC);
  mgr->ConnectInput(taskPWG4QAMC,0,mgr->GetCommonInputContainer());
  mgr->ConnectOutput(taskPWG4QAMC,0,cout_hist0);
  mgr->ConnectOutput(taskPWG4QAMC,1,cout_hist2);

  // Return task pointer at the end
  return taskPWG4QAMC;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"

#include <memory>

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/test/testsupport/fileutils.h"

namespace webrtc {

namespace {
static const int kHeaderSize = 32;
static const int kFrameHeaderSize = 12;
static uint8_t dummy_payload[4] = {0, 1, 2, 3};
static const int kMaxFileRetries = 5;
}  // namespace

class IvfFileWriterTest : public ::testing::Test {
 protected:
  void SetUp() override {
    const int64_t start_id =
        reinterpret_cast<int64_t>(this) ^ rtc::TimeMicros();
    int64_t id = start_id;
    do {
      std::ostringstream oss;
      oss << test::OutputPath() << "ivf_test_file_" << id++ << ".ivf";
      file_name_ = oss.str();
    } while (id < start_id + 100 && FileExists(false));
    ASSERT_LT(id, start_id + 100);
  }

  bool WriteDummyTestFrames(int width,
                            int height,
                            int num_frames,
                            bool use_capture_tims_ms) {
    EncodedImage frame;
    frame._buffer = dummy_payload;
    frame._encodedWidth = width;
    frame._encodedHeight = height;
    for (int i = 1; i <= num_frames; ++i) {
      frame._length = i % sizeof(dummy_payload);
      if (use_capture_tims_ms) {
        frame.capture_time_ms_ = i;
      } else {
        frame._timeStamp = i;
      }
      if (!file_writer_->WriteFrame(frame))
        return false;
    }
    return true;
  }

  void VerifyIvfHeader(FileWrapper* file,
                       const uint8_t fourcc[4],
                       int width,
                       int height,
                       uint32_t num_frames,
                       bool use_capture_tims_ms) {
    ASSERT_TRUE(file->is_open());
    uint8_t data[kHeaderSize];
    ASSERT_EQ(kHeaderSize, file->Read(data, kHeaderSize));

    uint8_t dkif[4] = {'D', 'K', 'I', 'F'};
    EXPECT_EQ(0, memcmp(dkif, data, 4));
    EXPECT_EQ(0u, ByteReader<uint16_t>::ReadLittleEndian(&data[4]));
    EXPECT_EQ(32u, ByteReader<uint16_t>::ReadLittleEndian(&data[6]));
    EXPECT_EQ(0, memcmp(fourcc, &data[8], 4));
    EXPECT_EQ(width, ByteReader<uint16_t>::ReadLittleEndian(&data[12]));
    EXPECT_EQ(height, ByteReader<uint16_t>::ReadLittleEndian(&data[14]));
    EXPECT_EQ(use_capture_tims_ms ? 1000u : 90000u,
              ByteReader<uint32_t>::ReadLittleEndian(&data[16]));
    EXPECT_EQ(1u, ByteReader<uint32_t>::ReadLittleEndian(&data[20]));
    EXPECT_EQ(num_frames, ByteReader<uint32_t>::ReadLittleEndian(&data[24]));
    EXPECT_EQ(0u, ByteReader<uint32_t>::ReadLittleEndian(&data[28]));
  }

  void VerifyDummyTestFrames(FileWrapper* file, uint32_t num_frames) {
    const int kMaxFrameSize = 4;
    for (uint32_t i = 1; i <= num_frames; ++i) {
      uint8_t frame_header[kFrameHeaderSize];
      ASSERT_EQ(kFrameHeaderSize, file->Read(frame_header, kFrameHeaderSize));
      uint32_t frame_length =
          ByteReader<uint32_t>::ReadLittleEndian(&frame_header[0]);
      EXPECT_EQ(i % 4, frame_length);
      uint64_t timestamp =
          ByteReader<uint64_t>::ReadLittleEndian(&frame_header[4]);
      EXPECT_EQ(i, timestamp);

      uint8_t data[kMaxFrameSize] = {};
      ASSERT_EQ(frame_length,
                static_cast<uint32_t>(file->Read(data, frame_length)));
      EXPECT_EQ(0, memcmp(data, dummy_payload, frame_length));
    }
  }

  void RunBasicFileStructureTest(VideoCodecType codec_type,
                                 const uint8_t fourcc[4],
                                 bool use_capture_tims_ms) {
    file_writer_ = IvfFileWriter::Open(file_name_, codec_type);
    ASSERT_TRUE(file_writer_.get());
    const int kWidth = 320;
    const int kHeight = 240;
    const int kNumFrames = 257;
    EXPECT_TRUE(
        WriteDummyTestFrames(kWidth, kHeight, kNumFrames, use_capture_tims_ms));
    EXPECT_TRUE(file_writer_->Close());

    std::unique_ptr<FileWrapper> out_file(FileWrapper::Create());
    ASSERT_TRUE(out_file->OpenFile(file_name_.c_str(), true));
    VerifyIvfHeader(out_file.get(), fourcc, kWidth, kHeight, kNumFrames,
                    use_capture_tims_ms);
    VerifyDummyTestFrames(out_file.get(), kNumFrames);

    out_file->CloseFile();

    bool file_removed = false;
    for (int i = 0; i < kMaxFileRetries; ++i) {
      file_removed = remove(file_name_.c_str()) == 0;
      if (file_removed)
        break;

      // Couldn't remove file for some reason, wait a sec and try again.
      rtc::Thread::SleepMs(1000);
    }
    EXPECT_TRUE(file_removed);
  }

  // Check whether file exists or not, and if it does not meet expectation,
  // wait a bit and check again, up to kMaxFileRetries times. This is an ugly
  // hack to avoid flakiness on certain operating systems where antivirus
  // software may unexpectedly lock files and keep them from disappearing or
  // being reused.
  bool FileExists(bool expected) {
    bool file_exists = expected;
    std::unique_ptr<FileWrapper> file_wrapper;
    int iterations = 0;
    do {
      if (file_wrapper.get() != nullptr)
        rtc::Thread::SleepMs(1000);
      file_wrapper.reset(FileWrapper::Create());
      file_exists = file_wrapper->OpenFile(file_name_.c_str(), true);
      file_wrapper->CloseFile();
    } while (file_exists != expected && ++iterations < kMaxFileRetries);
    return file_exists;
  }

  std::string file_name_;
  std::unique_ptr<IvfFileWriter> file_writer_;
};

TEST_F(IvfFileWriterTest, RemovesUnusedFile) {
  file_writer_ = IvfFileWriter::Open(file_name_, kVideoCodecVP8);
  ASSERT_TRUE(file_writer_.get() != nullptr);
  EXPECT_TRUE(FileExists(true));
  EXPECT_TRUE(file_writer_->Close());
  EXPECT_FALSE(FileExists(false));
  EXPECT_FALSE(file_writer_->Close());  // Can't close twice.
}

TEST_F(IvfFileWriterTest, WritesBasicVP8FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
  RunBasicFileStructureTest(kVideoCodecVP8, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicVP8FileMsTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
  RunBasicFileStructureTest(kVideoCodecVP8, fourcc, true);
}

TEST_F(IvfFileWriterTest, WritesBasicVP9FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '9', '0'};
  RunBasicFileStructureTest(kVideoCodecVP9, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicVP9FileMsTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '9', '0'};
  RunBasicFileStructureTest(kVideoCodecVP9, fourcc, true);
}

TEST_F(IvfFileWriterTest, WritesBasicH264FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'H', '2', '6', '4'};
  RunBasicFileStructureTest(kVideoCodecH264, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicH264FileMsTimestamp) {
  const uint8_t fourcc[4] = {'H', '2', '6', '4'};
  RunBasicFileStructureTest(kVideoCodecH264, fourcc, true);
}

}  // namespace webrtc
<commit_msg>Use a better method to generate a random ID in IvfFileWriterTest.<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"

#include <memory>

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/test/testsupport/fileutils.h"

namespace webrtc {

namespace {
static const int kHeaderSize = 32;
static const int kFrameHeaderSize = 12;
static uint8_t dummy_payload[4] = {0, 1, 2, 3};
static const int kMaxFileRetries = 5;
}  // namespace

class IvfFileWriterTest : public ::testing::Test {
 protected:
  void SetUp() override {
    const uint64_t start_id = rtc::CreateRandomId64();
    uint64_t id = start_id;
    do {
      std::ostringstream oss;
      oss << test::OutputPath() << "ivf_test_file_" << id++ << ".ivf";
      file_name_ = oss.str();
    } while ((id - start_id) < 100u && FileExists(false));
    ASSERT_LT(id - start_id, 100u);
  }

  bool WriteDummyTestFrames(int width,
                            int height,
                            int num_frames,
                            bool use_capture_tims_ms) {
    EncodedImage frame;
    frame._buffer = dummy_payload;
    frame._encodedWidth = width;
    frame._encodedHeight = height;
    for (int i = 1; i <= num_frames; ++i) {
      frame._length = i % sizeof(dummy_payload);
      if (use_capture_tims_ms) {
        frame.capture_time_ms_ = i;
      } else {
        frame._timeStamp = i;
      }
      if (!file_writer_->WriteFrame(frame))
        return false;
    }
    return true;
  }

  void VerifyIvfHeader(FileWrapper* file,
                       const uint8_t fourcc[4],
                       int width,
                       int height,
                       uint32_t num_frames,
                       bool use_capture_tims_ms) {
    ASSERT_TRUE(file->is_open());
    uint8_t data[kHeaderSize];
    ASSERT_EQ(kHeaderSize, file->Read(data, kHeaderSize));

    uint8_t dkif[4] = {'D', 'K', 'I', 'F'};
    EXPECT_EQ(0, memcmp(dkif, data, 4));
    EXPECT_EQ(0u, ByteReader<uint16_t>::ReadLittleEndian(&data[4]));
    EXPECT_EQ(32u, ByteReader<uint16_t>::ReadLittleEndian(&data[6]));
    EXPECT_EQ(0, memcmp(fourcc, &data[8], 4));
    EXPECT_EQ(width, ByteReader<uint16_t>::ReadLittleEndian(&data[12]));
    EXPECT_EQ(height, ByteReader<uint16_t>::ReadLittleEndian(&data[14]));
    EXPECT_EQ(use_capture_tims_ms ? 1000u : 90000u,
              ByteReader<uint32_t>::ReadLittleEndian(&data[16]));
    EXPECT_EQ(1u, ByteReader<uint32_t>::ReadLittleEndian(&data[20]));
    EXPECT_EQ(num_frames, ByteReader<uint32_t>::ReadLittleEndian(&data[24]));
    EXPECT_EQ(0u, ByteReader<uint32_t>::ReadLittleEndian(&data[28]));
  }

  void VerifyDummyTestFrames(FileWrapper* file, uint32_t num_frames) {
    const int kMaxFrameSize = 4;
    for (uint32_t i = 1; i <= num_frames; ++i) {
      uint8_t frame_header[kFrameHeaderSize];
      ASSERT_EQ(kFrameHeaderSize, file->Read(frame_header, kFrameHeaderSize));
      uint32_t frame_length =
          ByteReader<uint32_t>::ReadLittleEndian(&frame_header[0]);
      EXPECT_EQ(i % 4, frame_length);
      uint64_t timestamp =
          ByteReader<uint64_t>::ReadLittleEndian(&frame_header[4]);
      EXPECT_EQ(i, timestamp);

      uint8_t data[kMaxFrameSize] = {};
      ASSERT_EQ(frame_length,
                static_cast<uint32_t>(file->Read(data, frame_length)));
      EXPECT_EQ(0, memcmp(data, dummy_payload, frame_length));
    }
  }

  void RunBasicFileStructureTest(VideoCodecType codec_type,
                                 const uint8_t fourcc[4],
                                 bool use_capture_tims_ms) {
    file_writer_ = IvfFileWriter::Open(file_name_, codec_type);
    ASSERT_TRUE(file_writer_.get());
    const int kWidth = 320;
    const int kHeight = 240;
    const int kNumFrames = 257;
    EXPECT_TRUE(
        WriteDummyTestFrames(kWidth, kHeight, kNumFrames, use_capture_tims_ms));
    EXPECT_TRUE(file_writer_->Close());

    std::unique_ptr<FileWrapper> out_file(FileWrapper::Create());
    ASSERT_TRUE(out_file->OpenFile(file_name_.c_str(), true));
    VerifyIvfHeader(out_file.get(), fourcc, kWidth, kHeight, kNumFrames,
                    use_capture_tims_ms);
    VerifyDummyTestFrames(out_file.get(), kNumFrames);

    out_file->CloseFile();

    bool file_removed = false;
    for (int i = 0; i < kMaxFileRetries; ++i) {
      file_removed = remove(file_name_.c_str()) == 0;
      if (file_removed)
        break;

      // Couldn't remove file for some reason, wait a sec and try again.
      rtc::Thread::SleepMs(1000);
    }
    EXPECT_TRUE(file_removed);
  }

  // Check whether file exists or not, and if it does not meet expectation,
  // wait a bit and check again, up to kMaxFileRetries times. This is an ugly
  // hack to avoid flakiness on certain operating systems where antivirus
  // software may unexpectedly lock files and keep them from disappearing or
  // being reused.
  bool FileExists(bool expected) {
    bool file_exists = expected;
    std::unique_ptr<FileWrapper> file_wrapper;
    int iterations = 0;
    do {
      if (file_wrapper.get() != nullptr)
        rtc::Thread::SleepMs(1000);
      file_wrapper.reset(FileWrapper::Create());
      file_exists = file_wrapper->OpenFile(file_name_.c_str(), true);
      file_wrapper->CloseFile();
    } while (file_exists != expected && ++iterations < kMaxFileRetries);
    return file_exists;
  }

  std::string file_name_;
  std::unique_ptr<IvfFileWriter> file_writer_;
};

TEST_F(IvfFileWriterTest, RemovesUnusedFile) {
  file_writer_ = IvfFileWriter::Open(file_name_, kVideoCodecVP8);
  ASSERT_TRUE(file_writer_.get() != nullptr);
  EXPECT_TRUE(FileExists(true));
  EXPECT_TRUE(file_writer_->Close());
  EXPECT_FALSE(FileExists(false));
  EXPECT_FALSE(file_writer_->Close());  // Can't close twice.
}

TEST_F(IvfFileWriterTest, WritesBasicVP8FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
  RunBasicFileStructureTest(kVideoCodecVP8, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicVP8FileMsTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
  RunBasicFileStructureTest(kVideoCodecVP8, fourcc, true);
}

TEST_F(IvfFileWriterTest, WritesBasicVP9FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '9', '0'};
  RunBasicFileStructureTest(kVideoCodecVP9, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicVP9FileMsTimestamp) {
  const uint8_t fourcc[4] = {'V', 'P', '9', '0'};
  RunBasicFileStructureTest(kVideoCodecVP9, fourcc, true);
}

TEST_F(IvfFileWriterTest, WritesBasicH264FileNtpTimestamp) {
  const uint8_t fourcc[4] = {'H', '2', '6', '4'};
  RunBasicFileStructureTest(kVideoCodecH264, fourcc, false);
}

TEST_F(IvfFileWriterTest, WritesBasicH264FileMsTimestamp) {
  const uint8_t fourcc[4] = {'H', '2', '6', '4'};
  RunBasicFileStructureTest(kVideoCodecH264, fourcc, true);
}

}  // namespace webrtc
<|endoftext|>