<commit_before>//**************************************************************
//*            OpenGLide - Glide to OpenGL Wrapper
//*             http://openglide.sourceforge.net
//*
//*           implementation of the PGUexture class
//*
//*         OpenGLide is OpenSource under LGPL license
//*              Originaly made by Fabio Barros
//*      Modified by Paul for Glidos (http://www.glidos.net)
//**************************************************************

#include "glogl.h"
#include "PGTexture.h"
#include "PGUTexture.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

PGUTexture::PGUTexture( void )
{
    for ( int i = 0; i < MAX_MM; i++ )
    {
        mm_info[ i ].valid = false;
    }

    m_free_mem = 0;
    m_free_id = 0;
    m_current_id = GR_NULL_MIPMAP_HANDLE;
}

PGUTexture::~PGUTexture( void )
{
}

GrMipMapId_t PGUTexture::AllocateMemory( GrChipID_t tmu, FxU8 odd_even_mask,
                                         int width, int height,
                                         GrTextureFormat_t fmt, GrMipMapMode_t mm_mode,
                                         GrLOD_t smallest_lod, GrLOD_t largest_lod,
                                         GrAspectRatio_t aspect,
                                         GrTextureClampMode_t s_clamp_mode,
                                         GrTextureClampMode_t t_clamp_mode,
                                         GrTextureFilterMode_t minfilter_mode,
                                         GrTextureFilterMode_t magfilter_mode,
                                         float lod_bias, FxBool trilinear )
{
    FxU32   size = 0;
    GrLOD_t lod;

    for ( lod = largest_lod; lod <= smallest_lod; lod++ )
    {
        size += PGTexture::MipMapMemRequired( lod, aspect, fmt );
    }

    size = ((size + 7) & ~7);

#ifdef OGL_UTEX
    GlideMsg( "Allocate id = %d size = %d\n", m_free_id, size );
#endif

    if ( ( m_free_id >= MAX_MM ) ||
         ( ( m_free_mem + size ) >= Textures->GetMemorySize( ) ) )
    {
#ifdef OGL_UTEX
        GlideMsg("Allocation failed\n");
#endif
        return GR_NULL_MIPMAP_HANDLE;
    }

    mm_info[ m_free_id ].odd_even_mask  = odd_even_mask;
    mm_info[ m_free_id ].width          = width;
    mm_info[ m_free_id ].height         = height;
    mm_info[ m_free_id ].format         = fmt;
    mm_info[ m_free_id ].mipmap_mode    = mm_mode;
    mm_info[ m_free_id ].lod_min        = smallest_lod;
    mm_info[ m_free_id ].lod_max        = largest_lod;
    mm_info[ m_free_id ].aspect_ratio   = aspect;
    mm_info[ m_free_id ].s_clamp_mode   = s_clamp_mode;
    mm_info[ m_free_id ].t_clamp_mode   = t_clamp_mode;
    mm_info[ m_free_id ].minfilter_mode = minfilter_mode;
    mm_info[ m_free_id ].magfilter_mode = magfilter_mode;
    //mm_info[ m_free_id ].lod_bias       = lod_bias;
    mm_info[ m_free_id ].trilinear      = trilinear;
    mm_info[ m_free_id ].valid          = FXTRUE;

    mm_start[ m_free_id ] = m_free_mem;

    m_free_mem += size;

    return m_free_id++;
}

void PGUTexture::DownloadMipMap( GrMipMapId_t mmid, const void *src, const GuNccTable *table )
{
#ifdef OGL_UTEX
    GlideMsg("Download id = %d ", mmid);
#endif

    if ( ( mmid >=0 ) && ( mmid < MAX_MM ) && ( mm_info[ mmid ].valid ) )
    {
        GrTexInfo info;

        info.aspectRatio = mm_info[ mmid ].aspect_ratio;
        info.format      = mm_info[ mmid ].format;
        info.largeLod    = mm_info[ mmid ].lod_max;
        info.smallLod    = mm_info[ mmid ].lod_min;
        info.data        = (void *)src;
#ifdef OGL_UTEX
        {
            FxU32 size = 0;

            for ( GrLOD_t lod = info.largeLod; lod <= info.smallLod; lod++ )
            {
                size += PGTexture::MipMapMemRequired( lod, info.aspectRatio, info.format );
            }

            GlideMsg( "size = %d\n", size );
        }
#endif

        grTexDownloadMipMap( 0, mm_start[ mmid ], mm_info[ mmid ].odd_even_mask, &info );
    }
#ifdef OGL_UTEX
    else
    {
        GlideMsg( "failed\n" );
    }
#endif
}

void PGUTexture::DownloadMipMapLevel( GrMipMapId_t mmid, GrLOD_t lod, const void **src )
{
}

void PGUTexture::MemReset( void )
{
#ifdef OGL_UTEX
    GlideMsg("Reset\n");
#endif

    for ( int i = 0; i < MAX_MM; i++ )
    {
        mm_info[ i ].valid = false;
    }

    m_free_mem = 0;
    m_free_id = 0;
    m_current_id = GR_NULL_MIPMAP_HANDLE;
}

void PGUTexture::Source( GrMipMapId_t id )
{
    if ( ( id >=0 ) && ( id < MAX_MM ) && ( mm_info[ id ].valid ) )
    {
        GrTexInfo info;

        info.aspectRatio = mm_info[ id ].aspect_ratio;
        info.format      = mm_info[ id ].format;
        info.largeLod    = mm_info[ id ].lod_max;
        info.smallLod    = mm_info[ id ].lod_min;

        grTexSource( 0, mm_start[ id ], mm_info[ id ].odd_even_mask, &info );
        grTexFilterMode( 0, mm_info[ id ].minfilter_mode, mm_info[ id ].magfilter_mode );
        grTexMipMapMode( 0, mm_info[ id ].mipmap_mode, mm_info[ id ].trilinear );
        grTexClampMode( 0, mm_info[ id ].s_clamp_mode, mm_info[ id ].t_clamp_mode );
        //grTexLodBiasValue( 0, mm_info[ id ].lod_bias );

        m_current_id = id;
    }
#ifdef OGL_UTEX
    else
    {
        GlideMsg( "TexSourcefailed\n" );
    }
#endif
}

GrMipMapInfo *PGUTexture::GetMipMapInfo( GrMipMapId_t mmid )
{
    return ( ( mmid >= 0 ) && ( mmid < MAX_MM ) &&
             ( mm_info[mmid].valid ) ? &( mm_info[ mmid ] ) : NULL );
}

FxBool PGUTexture::ChangeAttributes( GrMipMapId_t mmid, int width, int height,
                                     GrTextureFormat_t fmt, GrMipMapMode_t mm_mode,
                                     GrLOD_t smallest_lod, GrLOD_t largest_lod,
                                     GrAspectRatio_t aspect, GrTextureClampMode_t s_clamp_mode,
                                     GrTextureClampMode_t t_clamp_mode,
                                     GrTextureFilterMode_t minFilterMode,
                                     GrTextureFilterMode_t magFilterMode )
{
    return FXFALSE;
}

GrMipMapId_t PGUTexture::GetCurrentMipMap( GrChipID_t tmu )
{
    return m_current_id;
}

FxU32 PGUTexture::MemQueryAvail( GrChipID_t tmu )
{
    return Textures->GetMemorySize( ) - m_free_mem;
}
<commit_msg>Fix include casing for Linux.<commit_after>//**************************************************************
//*            OpenGLide - Glide to OpenGL Wrapper
//*             http://openglide.sourceforge.net
//*
//*           implementation of the PGUexture class
//*
//*         OpenGLide is OpenSource under LGPL license
//*              Originaly made by Fabio Barros
//*      Modified by Paul for Glidos (http://www.glidos.net)
//**************************************************************

#include "GlOgl.h"
#include "PGTexture.h"
#include "PGUTexture.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

PGUTexture::PGUTexture( void )
{
    for ( int i = 0; i < MAX_MM; i++ )
    {
        mm_info[ i ].valid = false;
    }

    m_free_mem = 0;
    m_free_id = 0;
    m_current_id = GR_NULL_MIPMAP_HANDLE;
}

PGUTexture::~PGUTexture( void )
{
}

GrMipMapId_t PGUTexture::AllocateMemory( GrChipID_t tmu, FxU8 odd_even_mask,
                                         int width, int height,
                                         GrTextureFormat_t fmt, GrMipMapMode_t mm_mode,
                                         GrLOD_t smallest_lod, GrLOD_t largest_lod,
                                         GrAspectRatio_t aspect,
                                         GrTextureClampMode_t s_clamp_mode,
                                         GrTextureClampMode_t t_clamp_mode,
                                         GrTextureFilterMode_t minfilter_mode,
                                         GrTextureFilterMode_t magfilter_mode,
                                         float lod_bias, FxBool trilinear )
{
    FxU32   size = 0;
    GrLOD_t lod;

    for ( lod = largest_lod; lod <= smallest_lod; lod++ )
    {
        size += PGTexture::MipMapMemRequired( lod, aspect, fmt );
    }

    size = ((size + 7) & ~7);

#ifdef OGL_UTEX
    GlideMsg( "Allocate id = %d size = %d\n", m_free_id, size );
#endif

    if ( ( m_free_id >= MAX_MM ) ||
         ( ( m_free_mem + size ) >= Textures->GetMemorySize( ) ) )
    {
#ifdef OGL_UTEX
        GlideMsg("Allocation failed\n");
#endif
        return GR_NULL_MIPMAP_HANDLE;
    }

    mm_info[ m_free_id ].odd_even_mask  = odd_even_mask;
    mm_info[ m_free_id ].width          = width;
    mm_info[ m_free_id ].height         = height;
    mm_info[ m_free_id ].format         = fmt;
    mm_info[ m_free_id ].mipmap_mode    = mm_mode;
    mm_info[ m_free_id ].lod_min        = smallest_lod;
    mm_info[ m_free_id ].lod_max        = largest_lod;
    mm_info[ m_free_id ].aspect_ratio   = aspect;
    mm_info[ m_free_id ].s_clamp_mode   = s_clamp_mode;
    mm_info[ m_free_id ].t_clamp_mode   = t_clamp_mode;
    mm_info[ m_free_id ].minfilter_mode = minfilter_mode;
    mm_info[ m_free_id ].magfilter_mode = magfilter_mode;
    //mm_info[ m_free_id ].lod_bias       = lod_bias;
    mm_info[ m_free_id ].trilinear      = trilinear;
    mm_info[ m_free_id ].valid          = FXTRUE;

    mm_start[ m_free_id ] = m_free_mem;

    m_free_mem += size;

    return m_free_id++;
}

void PGUTexture::DownloadMipMap( GrMipMapId_t mmid, const void *src, const GuNccTable *table )
{
#ifdef OGL_UTEX
    GlideMsg("Download id = %d ", mmid);
#endif

    if ( ( mmid >=0 ) && ( mmid < MAX_MM ) && ( mm_info[ mmid ].valid ) )
    {
        GrTexInfo info;

        info.aspectRatio = mm_info[ mmid ].aspect_ratio;
        info.format      = mm_info[ mmid ].format;
        info.largeLod    = mm_info[ mmid ].lod_max;
        info.smallLod    = mm_info[ mmid ].lod_min;
        info.data        = (void *)src;
#ifdef OGL_UTEX
        {
            FxU32 size = 0;

            for ( GrLOD_t lod = info.largeLod; lod <= info.smallLod; lod++ )
            {
                size += PGTexture::MipMapMemRequired( lod, info.aspectRatio, info.format );
            }

            GlideMsg( "size = %d\n", size );
        }
#endif

        grTexDownloadMipMap( 0, mm_start[ mmid ], mm_info[ mmid ].odd_even_mask, &info );
    }
#ifdef OGL_UTEX
    else
    {
        GlideMsg( "failed\n" );
    }
#endif
}

void PGUTexture::DownloadMipMapLevel( GrMipMapId_t mmid, GrLOD_t lod, const void **src )
{
}

void PGUTexture::MemReset( void )
{
#ifdef OGL_UTEX
    GlideMsg("Reset\n");
#endif

    for ( int i = 0; i < MAX_MM; i++ )
    {
        mm_info[ i ].valid = false;
    }

    m_free_mem = 0;
    m_free_id = 0;
    m_current_id = GR_NULL_MIPMAP_HANDLE;
}

void PGUTexture::Source( GrMipMapId_t id )
{
    if ( ( id >=0 ) && ( id < MAX_MM ) && ( mm_info[ id ].valid ) )
    {
        GrTexInfo info;

        info.aspectRatio = mm_info[ id ].aspect_ratio;
        info.format      = mm_info[ id ].format;
        info.largeLod    = mm_info[ id ].lod_max;
        info.smallLod    = mm_info[ id ].lod_min;

        grTexSource( 0, mm_start[ id ], mm_info[ id ].odd_even_mask, &info );
        grTexFilterMode( 0, mm_info[ id ].minfilter_mode, mm_info[ id ].magfilter_mode );
        grTexMipMapMode( 0, mm_info[ id ].mipmap_mode, mm_info[ id ].trilinear );
        grTexClampMode( 0, mm_info[ id ].s_clamp_mode, mm_info[ id ].t_clamp_mode );
        //grTexLodBiasValue( 0, mm_info[ id ].lod_bias );

        m_current_id = id;
    }
#ifdef OGL_UTEX
    else
    {
        GlideMsg( "TexSourcefailed\n" );
    }
#endif
}

GrMipMapInfo *PGUTexture::GetMipMapInfo( GrMipMapId_t mmid )
{
    return ( ( mmid >= 0 ) && ( mmid < MAX_MM ) &&
             ( mm_info[mmid].valid ) ? &( mm_info[ mmid ] ) : NULL );
}

FxBool PGUTexture::ChangeAttributes( GrMipMapId_t mmid, int width, int height,
                                     GrTextureFormat_t fmt, GrMipMapMode_t mm_mode,
                                     GrLOD_t smallest_lod, GrLOD_t largest_lod,
                                     GrAspectRatio_t aspect, GrTextureClampMode_t s_clamp_mode,
                                     GrTextureClampMode_t t_clamp_mode,
                                     GrTextureFilterMode_t minFilterMode,
                                     GrTextureFilterMode_t magFilterMode )
{
    return FXFALSE;
}

GrMipMapId_t PGUTexture::GetCurrentMipMap( GrChipID_t tmu )
{
    return m_current_id;
}

FxU32 PGUTexture::MemQueryAvail( GrChipID_t tmu )
{
    return Textures->GetMemorySize( ) - m_free_mem;
}
<|endoftext|>


<commit_before>// Steer TRD QA train for Reconstruction (Clusterizer, Tracking and PID).
//
// Usage:
//   run.C(tasks, files)
//   tasks : "ALL" or one/more of the following:
//     "EFF"  : TRD Tracking Efficiency
//     "EFFC" : TRD Tracking Efficiency Combined (barrel + stand alone) - only in case of simulations
//     "MULT"  : TRD single track selection
//     "RES"  : TRD tracking Resolution
//     "CLRES": clusters Resolution
//     "CAL"  : TRD calibration
//     "ALGN" : TRD alignment
//     "PID"  : TRD PID - pion efficiency
//     "PIDR" : TRD PID - reference data
//     "DET"  : Basic TRD Detector checks
//     "NOFR" : Data set does not have AliESDfriends.root
//     "NOMC" : Data set does not have Monte Carlo Informations (real data), so all tasks which rely
//              on MC information are switched off
//
// In compiled mode :
// Don't forget to load first the libraries
// gSystem->Load("libMemStat.so")
// gSystem->Load("libMemStatGui.so")
// gSystem->Load("libANALYSIS.so")
// gSystem->Load("libANALYSISalice.so")
// gSystem->Load("libPWG1.so");
// gSystem->Load("libNetx.so") ;
// gSystem->Load("libRAliEn.so");
//
// Authors:
//   Alex Bercuci (A.Bercuci@gsi.de)
//   Markus Fasel (m.Fasel@gsi.de)

#if ! defined (__CINT__) || defined (__MAKECINT__)
//#ifndef __CINT__
#include <Riostream.h>

#include "TStopwatch.h"
#include "TMemStat.h"
#include "TMemStatViewerGUI.h"

#include "TROOT.h"
#include "TClass.h"
#include "TSystem.h"
#include "TError.h"
#include "TChain.h"
#include "TGrid.h"
#include "TAlienCollection.h"
#include "TGridCollection.h"
#include "TGridResult.h"
#include "TGeoGlobalMagField.h"

#include "AliMagF.h"
#include "AliTracker.h"
#include "AliLog.h"
#include "AliCDBManager.h"
#include "AliGRPManager.h"
#include "AliGeomManager.h"
#include "AliAnalysisManager.h"
#include "AliAnalysisDataContainer.h"
#include "AliMCEventHandler.h"
#include "AliESDInputHandler.h"

#include "TRD/AliTRDtrackerV1.h"
#include "TRD/AliTRDcalibDB.h"

#include "PWG1/TRD/macros/AliTRDperformanceTrain.h"
#include "PWG1/TRD/macros/AddTRDcheckESD.C"
#include "PWG1/TRD/macros/AddTRDinfoGen.C"
#include "PWG1/TRD/macros/AddTRDcheckDET.C"
#include "PWG1/TRD/macros/AddTRDefficiency.C"
#include "PWG1/TRD/macros/AddTRDresolution.C"
#include "PWG1/TRD/macros/AddTRDcheckPID.C"

#endif

#include "macros/AliTRDperformanceTrain.h"

Bool_t MEM = kFALSE;

TChain* MakeChainLST(const char* filename = 0x0);
TChain* MakeChainXML(const char* filename = 0x0);
void run(Char_t *trd="ALL", const Char_t *files=0x0, Long64_t nev=1234567890, Long64_t first = 0)
{
  TMemStat *mem = 0x0;
  if(MEM){
    gSystem->Load("libMemStat.so");
    gSystem->Load("libMemStatGui.so");
    mem = new TMemStat("new, gnubuildin");
    mem->AddStamp("Start");
  }
  TStopwatch timer;
  timer.Start();

  // VERY GENERAL SETTINGS
  AliLog::SetGlobalLogLevel(AliLog::kError);
  if(gSystem->Load("libANALYSIS.so")<0) return;
  if(gSystem->Load("libANALYSISalice.so")<0) return;
  if(gSystem->Load("libTENDER.so")<0) return;
  if(gSystem->Load("libPWG1.so")<0) return;

  Bool_t fHasMCdata =  HasReadMCData(trd);
  Bool_t fHasFriends = HasReadFriendData(trd);

  // INITIALIZATION OF RUNNING ENVIRONMENT
  //TODO We should use the GRP if available similar to AliReconstruction::InitGRP()!
  // initialize OCDB manager
  AliCDBManager *cdbManager = AliCDBManager::Instance();
  cdbManager->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
  cdbManager->SetSpecificStorage("GRP/GRP/Data", Form("local://%s",gSystem->pwd()));
  cdbManager->SetRun(0);
  cdbManager->SetCacheFlag(kFALSE);
  // initialize magnetic field from the GRP manager.
  AliGRPManager grpMan;
  grpMan.ReadGRPEntry();
  grpMan.SetMagField();
  //AliRunInfo *runInfo = grpMan.GetRunInfo();
  AliGeomManager::LoadGeometry();

  // DEFINE DATA CHAIN
  TChain *chain = 0x0;
  if(!files) chain = MakeChainLST();
  else{
    TString fn(files);
    if(fn.EndsWith("xml")) chain = MakeChainXML(files);
    else chain = MakeChainLST(files);
  }
  if(!chain) return;
  chain->SetBranchStatus("*FMD*",0);
  chain->SetBranchStatus("*Calo*",0);
  chain->SetBranchStatus("Tracks", 1);
  chain->SetBranchStatus("ESDfriend*",1);
  chain->Lookup();
  chain->GetListOfFiles()->Print();
  printf("\n ----> CHAIN HAS %d ENTRIES <----\n\n", (Int_t)chain->GetEntries());

  // BUILD ANALYSIS MANAGER
  AliAnalysisManager *mgr = new AliAnalysisManager("Post Reconstruction Calibration/QA");
  AliVEventHandler *esdH = 0x0, *mcH = 0x0;
  mgr->SetInputEventHandler(esdH = new AliESDInputHandler);
  if(fHasMCdata) mgr->SetMCtruthEventHandler(mcH = new AliMCEventHandler());
  //mgr->SetDebugLevel(10);

  gROOT->LoadMacro("$ALICE_ROOT/PWG1/macros/AddTrainPerformanceTRD.C");
  if(! AddTrainPerformanceTRD(fHasMCdata, fHasFriends, trd)) {
    Error("run.C", "Error loading TRD train.");
    return;
  }

  if (!mgr->InitAnalysis()) return;
  // verbosity
  printf("\n\tRUNNING TRAIN FOR TASKS:\n");
  mgr->GetTasks()->ls();
  //mgr->PrintStatus();

  mgr->StartAnalysis("local", chain, nev, first);

  timer.Stop();
  timer.Print();

  TGeoGlobalMagField::Instance()->SetField(NULL);
  delete cdbManager;

  // verbosity
  printf("\n\tCLEANING UP TRAIN:\n");
  mgr->GetTasks()->Delete();

  if(mcH) delete mcH;
  delete esdH;
  delete mgr;
  delete chain;
  if(MEM) delete mem;
  if(MEM) TMemStatViewerGUI::ShowGUI();
}

//____________________________________________
TChain* MakeChainLST(const char* filename)
{
  // Create the chain
  TChain* chain = new TChain("esdTree");

  if(!filename){
    chain->Add(Form("%s/AliESDs.root", gSystem->pwd()));
    return chain;
  }

  // read ESD files from the input list.
  ifstream in;
  in.open(filename);
  TString esdfile;
  while(in.good()) {
    in >> esdfile;
    if (!esdfile.Contains("root")) continue; // protection
    chain->Add(esdfile.Data());
  }

  in.close();

  return chain;
}

//____________________________________________
TChain* MakeChainXML(const char* xmlfile)
{
  if (!TFile::Open(xmlfile)) {
    Error("MakeChainXML", Form("No file %s was found", xmlfile));
    return 0x0;
  }

  if(gSystem->Load("libNetx.so")<0) return 0x0;
  if(gSystem->Load("libRAliEn.so")<0) return 0x0;
  TGrid::Connect("alien://") ;

  TGridCollection *collection = (TGridCollection*) TAlienCollection::Open(xmlfile);
  if (!collection) {
    Error("MakeChainXML", Form("No collection found in %s", xmlfile)) ;
    return 0x0;
  }
  //collection->CheckIfOnline();

  TGridResult* result = collection->GetGridResult("",0 ,0);
  if(!result->GetEntries()){
    Error("MakeChainXML", Form("No entries found in %s", xmlfile)) ;
    return 0x0;
  }
  // Makes the ESD chain
  TChain* chain = new TChain("esdTree");
  for (Int_t idx = 0; idx < result->GetEntries(); idx++) {
    chain->Add(result->GetKey(idx, "turl"));
  }
  return chain;
}
<commit_msg>move setting OCDB and GRP from default to user responsibility. Default for local MC<commit_after>// Steer TRD QA train for Reconstruction (Clusterizer, Tracking and PID).
//
// Usage:
//   run.C(tasks, files)
//   tasks : "ALL" or one/more of the following:
//     "EFF"  : TRD Tracking Efficiency
//     "EFFC" : TRD Tracking Efficiency Combined (barrel + stand alone) - only in case of simulations
//     "MULT"  : TRD single track selection
//     "RES"  : TRD tracking Resolution
//     "CLRES": clusters Resolution
//     "CAL"  : TRD calibration
//     "ALGN" : TRD alignment
//     "PID"  : TRD PID - pion efficiency
//     "PIDR" : TRD PID - reference data
//     "DET"  : Basic TRD Detector checks
//     "NOFR" : Data set does not have AliESDfriends.root
//     "NOMC" : Data set does not have Monte Carlo Informations (real data), so all tasks which rely
//              on MC information are switched off
//
// In compiled mode :
// Don't forget to load first the libraries
// gSystem->Load("libMemStat.so")
// gSystem->Load("libMemStatGui.so")
// gSystem->Load("libANALYSIS.so")
// gSystem->Load("libANALYSISalice.so")
// gSystem->Load("libPWG1.so");
// gSystem->Load("libNetx.so") ;
// gSystem->Load("libRAliEn.so");
//
// Authors:
//   Alex Bercuci (A.Bercuci@gsi.de)
//   Markus Fasel (m.Fasel@gsi.de)

#if ! defined (__CINT__) || defined (__MAKECINT__)
//#ifndef __CINT__
#include <Riostream.h>

#include "TStopwatch.h"
#include "TMemStat.h"
#include "TMemStatViewerGUI.h"

#include "TROOT.h"
#include "TClass.h"
#include "TSystem.h"
#include "TError.h"
#include "TChain.h"
#include "TGrid.h"
#include "TAlienCollection.h"
#include "TGridCollection.h"
#include "TGridResult.h"
#include "TGeoGlobalMagField.h"

#include "AliMagF.h"
#include "AliTracker.h"
#include "AliLog.h"
#include "AliCDBManager.h"
#include "AliGRPManager.h"
#include "AliGeomManager.h"
#include "AliAnalysisManager.h"
#include "AliAnalysisDataContainer.h"
#include "AliMCEventHandler.h"
#include "AliESDInputHandler.h"

#include "TRD/AliTRDtrackerV1.h"
#include "TRD/AliTRDcalibDB.h"

#include "PWG1/TRD/macros/AliTRDperformanceTrain.h"
#include "PWG1/TRD/macros/AddTRDcheckESD.C"
#include "PWG1/TRD/macros/AddTRDinfoGen.C"
#include "PWG1/TRD/macros/AddTRDcheckDET.C"
#include "PWG1/TRD/macros/AddTRDefficiency.C"
#include "PWG1/TRD/macros/AddTRDresolution.C"
#include "PWG1/TRD/macros/AddTRDcheckPID.C"

#endif

#include "macros/AliTRDperformanceTrain.h"

Bool_t MEM = kFALSE;

TChain* MakeChainLST(const char* filename = 0x0);
TChain* MakeChainXML(const char* filename = 0x0);
void run(Char_t *optList="ALL", const Char_t *files=0x0, Long64_t nev=1234567890, Long64_t first = 0, Int_t runNo=0, const Char_t *ocdb_uri="local://$ALICE_ROOT/OCDB", const Char_t *grp_uri=Form("local://%s", gSystem->pwd()))
{
  TMemStat *mem = 0x0;
  if(MEM){
    gSystem->Load("libMemStat.so");
    gSystem->Load("libMemStatGui.so");
    mem = new TMemStat("new, gnubuildin");
    mem->AddStamp("Start");
  }
  TStopwatch timer;
  timer.Start();

  // VERY GENERAL SETTINGS
  AliLog::SetGlobalLogLevel(AliLog::kError);
  if(gSystem->Load("libANALYSIS.so")<0) return;
  if(gSystem->Load("libANALYSISalice.so")<0) return;
  if(gSystem->Load("libTENDER.so")<0) return;
  if(gSystem->Load("libPWG1.so")<0) return;

  Bool_t fHasMCdata =  HasReadMCData(optList);
  Bool_t fHasFriends = HasReadFriendData(optList);

  // INITIALIZATION OF RUNNING ENVIRONMENT
  // initialize OCDB manager
  AliCDBManager *cdbManager = AliCDBManager::Instance();
  cdbManager->SetDefaultStorage(ocdb_uri);
  if(!cdbManager->IsDefaultStorageSet()){
    Error("run.C", "Error setting OCDB.");
    return;
  }
  cdbManager->SetRun(runNo);
  cdbManager->SetSpecificStorage("GRP/GRP/Data", grp_uri);
  cdbManager->SetCacheFlag(kFALSE);
  // initialize magnetic field from the GRP manager.
  AliGRPManager grpMan;
  if(!grpMan.ReadGRPEntry()) return;
  if(!grpMan.SetMagField()) return;
  //AliRunInfo *runInfo = grpMan.GetRunInfo();
  AliGeomManager::LoadGeometry();

  // DEFINE DATA CHAIN
  TChain *chain = 0x0;
  if(!files) chain = MakeChainLST();
  else{
    TString fn(files);
    if(fn.EndsWith("xml")) chain = MakeChainXML(files);
    else chain = MakeChainLST(files);
  }
  if(!chain) return;
  chain->SetBranchStatus("*FMD*",0);
  chain->SetBranchStatus("*Calo*",0);
  chain->SetBranchStatus("Tracks", 1);
  chain->SetBranchStatus("ESDfriend*",1);
  chain->Lookup();
  chain->GetListOfFiles()->Print();
  printf("\n ----> CHAIN HAS %d ENTRIES <----\n\n", (Int_t)chain->GetEntries());

  // BUILD ANALYSIS MANAGER
  AliAnalysisManager *mgr = new AliAnalysisManager("Post Reconstruction Calibration/QA");
  AliVEventHandler *esdH = 0x0, *mcH = 0x0;
  mgr->SetInputEventHandler(esdH = new AliESDInputHandler);
  if(fHasMCdata) mgr->SetMCtruthEventHandler(mcH = new AliMCEventHandler());
  //mgr->SetDebugLevel(10);

  gROOT->LoadMacro("$ALICE_ROOT/PWG1/macros/AddTrainPerformanceTRD.C");
  if(! AddTrainPerformanceTRD(fHasMCdata, fHasFriends, optList)) {
    Error("run.C", "Error loading TRD train.");
    return;
  }

  if (!mgr->InitAnalysis()) return;
  // verbosity
  printf("\n\tRUNNING TRAIN FOR TASKS:\n");
  mgr->GetTasks()->ls();
  //mgr->PrintStatus();

  mgr->StartAnalysis("local", chain, nev, first);

  timer.Stop();
  timer.Print();

  TGeoGlobalMagField::Instance()->SetField(NULL);
  delete cdbManager;

  // verbosity
  printf("\n\tCLEANING UP TRAIN:\n");
  mgr->GetTasks()->Delete();

  if(mcH) delete mcH;
  delete esdH;
  delete mgr;
  delete chain;
  if(MEM) delete mem;
  if(MEM) TMemStatViewerGUI::ShowGUI();
}

//____________________________________________
TChain* MakeChainLST(const char* filename)
{
  // Create the chain
  TChain* chain = new TChain("esdTree");

  if(!filename){
    chain->Add(Form("%s/AliESDs.root", gSystem->pwd()));
    return chain;
  }

  // read ESD files from the input list.
  ifstream in;
  in.open(filename);
  TString esdfile;
  while(in.good()) {
    in >> esdfile;
    if (!esdfile.Contains("root")) continue; // protection
    chain->Add(esdfile.Data());
  }

  in.close();

  return chain;
}

//____________________________________________
TChain* MakeChainXML(const char* xmlfile)
{
  if (!TFile::Open(xmlfile)) {
    Error("MakeChainXML", Form("No file %s was found", xmlfile));
    return 0x0;
  }

  if(gSystem->Load("libNetx.so")<0) return 0x0;
  if(gSystem->Load("libRAliEn.so")<0) return 0x0;
  TGrid::Connect("alien://") ;

  TGridCollection *collection = (TGridCollection*) TAlienCollection::Open(xmlfile);
  if (!collection) {
    Error("MakeChainXML", Form("No collection found in %s", xmlfile)) ;
    return 0x0;
  }
  //collection->CheckIfOnline();

  TGridResult* result = collection->GetGridResult("",0 ,0);
  if(!result->GetEntries()){
    Error("MakeChainXML", Form("No entries found in %s", xmlfile)) ;
    return 0x0;
  }
  // Makes the ESD chain
  TChain* chain = new TChain("esdTree");
  for (Int_t idx = 0; idx < result->GetEntries(); idx++) {
    chain->Add(result->GetKey(idx, "turl"));
  }
  return chain;
}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------------------------
// Copyright 2015 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies.  Intel makes no representations about the
// suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//--------------------------------------------------------------------------------------

#include "PresentMon.hpp"
#include "Util.hpp"
#include <algorithm>
#include <numeric>
#include <ctime>
#include <iterator>

#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>

#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "shlwapi.lib")

enum {
    MAX_HISTORY_TIME = 2000,
    MAX_DISPLAYED_HISTORY_TIME = 2000,
    CHAIN_TIMEOUT_THRESHOLD_TICKS = 10000 // 10 sec
};

template <typename Map, typename F>
static void map_erase_if(Map& m, F pred)
{
    typename Map::iterator i = m.begin();
    while ((i = std::find_if(i, m.end(), pred)) != m.end())
        m.erase(i++);
}

static void UpdateProcessInfo_Realtime(ProcessInfo& info, uint64_t now, uint32_t thisPid)
{
    if (now - info.mLastRefreshTicks > 1000) {
        info.mLastRefreshTicks = now;
        char path[MAX_PATH] = "<error>";
        HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, thisPid);
        if (h) {
            GetModuleFileNameExA(h, NULL, path, sizeof(path) - 1);
            std::string name = PathFindFileNameA(path);
            if (name != info.mModuleName) {
                info.mChainMap.clear();
                info.mModuleName = name;
            }
            CloseHandle(h);
        } else {
            info.mChainMap.clear();
        }
    }
    // remove chains without recent updates
    map_erase_if(info.mChainMap, [now](const std::pair<const uint64_t, SwapChainData>& entry) {
        return now - entry.second.mLastUpdateTicks > CHAIN_TIMEOUT_THRESHOLD_TICKS;
    });
}

const char* PresentModeToString(PresentMode mode)
{
    switch (mode) {
    case PresentMode::Hardware_Legacy_Flip: return "Hardware: Legacy Flip";
    case PresentMode::Hardware_Legacy_Copy_To_Front_Buffer: return "Hardware: Legacy Copy to front buffer";
    case PresentMode::Hardware_Direct_Flip: return "Hardware: Direct Flip";
    case PresentMode::Hardware_Independent_Flip: return "Hardware: Independent Flip";
    case PresentMode::Composed_Flip: return "Composed: Flip";
    case PresentMode::Composed_Copy_GPU_GDI: return "Composed: Copy with GPU GDI";
    case PresentMode::Composed_Copy_CPU_GDI: return "Composed: Copy with CPU GDI";
    case PresentMode::Composed_Composition_Atlas: return "Composed: Composition Atlas";
    case PresentMode::Hardware_Composed_Independent_Flip: return "Hardware Composed: Independent Flip";
    default: return "Other";
    }
}

const char* RuntimeToString(Runtime rt)
{
    switch (rt) {
    case Runtime::DXGI: return "DXGI";
    case Runtime::D3D9: return "D3D9";
    default: return "Other";
    }
}

void PruneDeque(std::deque<PresentEvent> &presentHistory, uint64_t perfFreq, uint32_t msTimeDiff) {
    while (!presentHistory.empty() &&
           ((double)(presentHistory.back().QpcTime - presentHistory.front().QpcTime) / perfFreq) * 1000 > msTimeDiff) {
        presentHistory.pop_front();
    }
}

void AddPresent(PresentMonData& pm, PresentEvent& p, uint64_t now, uint64_t perfFreq)
{
    auto& proc = pm.mProcessMap[p.ProcessId];
    if (!proc.mLastRefreshTicks && !pm.mArgs->mEtlFileName) {
        UpdateProcessInfo_Realtime(proc, now, p.ProcessId);
    }

    if (pm.mArgs->mTargetProcessName && strcmp(pm.mArgs->mTargetProcessName, "*") &&
        _stricmp(pm.mArgs->mTargetProcessName, proc.mModuleName.c_str())) {
        // process name does not match
        return;
    }
    if (pm.mArgs->mTargetPid && p.ProcessId != pm.mArgs->mTargetPid) {
        return;
    }

    auto& chain = proc.mChainMap[p.SwapChainAddress];

    if (p.FinalState == PresentResult::Presented)
    {
        // FIXME: ensure that presents are always sorted before being passed here,
        // or add logic to handle that case here.
        assert(chain.mPresentHistory.empty() || chain.mPresentHistory.back().QpcTime < p.QpcTime);

        chain.mPresentHistory.push_back(p);
        chain.mDisplayedPresentHistory.push_back(p);

        auto numPresents = chain.mPresentHistory.size();
        for (int i = int(numPresents) - 1; i > 0; --i)
        {
            auto& curr = chain.mPresentHistory[i];
            auto& prev = chain.mPresentHistory[i - 1];
            if (curr.logged) break;
            curr.logged = true;

            double deltaMilliseconds = 1000 * double(curr.QpcTime - prev.QpcTime) / perfFreq;
            double deltaReady = curr.ReadyTime == 0 ? 0.0 : (1000 * double(curr.ReadyTime - curr.QpcTime) / perfFreq);
            double deltaDisplayed = curr.ScreenTime == 0 ? 0.0 : (1000 * double(curr.ScreenTime - curr.QpcTime) / perfFreq);
            double timeTakenMilliseconds = 1000 * double(curr.TimeTaken) / perfFreq;
            fprintf(pm.mOutputFile, "%s,%d,0x%016llX,%s,%.3lf,%.3lf,%d,%d,%s,%.3lf,%.3lf,%d\n",
                proc.mModuleName.c_str(), p.ProcessId, p.SwapChainAddress, RuntimeToString(p.Runtime),
                deltaMilliseconds, timeTakenMilliseconds, curr.SyncInterval, curr.PresentFlags, PresentModeToString(curr.PresentMode),
                deltaReady, deltaDisplayed, curr.FinalState != PresentResult::Discarded);
        }

        PruneDeque(chain.mDisplayedPresentHistory, perfFreq, MAX_DISPLAYED_HISTORY_TIME);
        PruneDeque(chain.mPresentHistory, perfFreq, MAX_HISTORY_TIME);
    } else {
        chain.mPresentHistory.push_back(p);
    }

    chain.mLastUpdateTicks = now;
    chain.mRuntime = p.Runtime;
    chain.mLastSyncInterval = p.SyncInterval;
    chain.mLastFlags = p.PresentFlags;
    chain.mLastPresentMode = p.PresentMode;
    chain.mLastPlane = p.PlaneIndex;
}

static double ComputeFps(const std::deque<PresentEvent>& presentHistory, uint64_t qpcFreq)
{
    if (presentHistory.size() < 2) {
        return 0.0;
    }
    auto start = presentHistory.front().QpcTime;
    auto end = presentHistory.back().QpcTime;
    auto count = presentHistory.size() - 1;

    double deltaT = double(end - start) / qpcFreq;
    return count / deltaT;
}

static double ComputeDisplayedFps(SwapChainData& stats, uint64_t qpcFreq)
{
    return ComputeFps(stats.mDisplayedPresentHistory, qpcFreq);
}

static double ComputeFps(SwapChainData& stats, uint64_t qpcFreq)
{
    return ComputeFps(stats.mPresentHistory, qpcFreq);
}

static double ComputeLatency(SwapChainData& stats, uint64_t qpcFreq)
{
    if (stats.mDisplayedPresentHistory.size() < 2) {
        return 0.0;
    }

    uint64_t totalLatency = std::accumulate(stats.mDisplayedPresentHistory.begin(), stats.mDisplayedPresentHistory.end() - 1, 0ull,
                                   [](uint64_t current, PresentEvent const& e) { return current + e.ScreenTime - e.QpcTime; });
    double average = ((double)(totalLatency) / qpcFreq) / (stats.mDisplayedPresentHistory.size() - 1);
    return average;
}

static double ComputeCpuFrameTime(SwapChainData& stats, uint64_t qpcFreq)
{
    if (stats.mPresentHistory.size() < 2) {
        return 0.0;
    }

    uint64_t timeInPresent = std::accumulate(stats.mPresentHistory.begin(), stats.mPresentHistory.end() - 1, 0ull,
                                   [](uint64_t current, PresentEvent const& e) { return current + e.TimeTaken; });
    uint64_t totalTime = stats.mPresentHistory.back().QpcTime - stats.mPresentHistory.front().QpcTime;

    double timeNotInPresent = double(totalTime - timeInPresent) / qpcFreq;
    return timeNotInPresent / (stats.mPresentHistory.size() - 1);
}

void PresentMon_Init(const PresentMonArgs& args, PresentMonData& pm)
{
    pm.mArgs = &args;

    if (args.mOutputFileName) {
        fopen_s(&pm.mOutputFile, args.mOutputFileName, "w");
    } else if (args.mTargetProcessName) {
        struct tm tm;
        time_t time_now = time(NULL);
        localtime_s(&tm, &time_now);
        std::string date = FormatString("%4d-%02d-%02d-%02d-%02d",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec);
        std::string path;
        if (strchr(args.mTargetProcessName, '*')) {
            path = FormatString("PresentMon-%s.csv", date.c_str());
        } else {
            path = FormatString("PresentMon-%s-%s.csv", args.mTargetProcessName, date.c_str());
        }
        fopen_s(&pm.mOutputFile, path.c_str(), "w");
    }

    if (pm.mOutputFile) {
        fprintf(pm.mOutputFile, "module,pid,chain,runtime,delta,timeTaken,vsync,flags,mode,deltaReady,deltaDisplayed,displayed\n");
    }
}

void PresentMon_UpdateNewProcesses(PresentMonData& pm, std::map<uint32_t, ProcessInfo>& newProcesses)
{
    for (auto processPair : newProcesses) {
        pm.mProcessMap[processPair.first] = processPair.second;
    }
}

void PresentMon_UpdateDeadProcesses(PresentMonData& pm, std::vector<uint32_t>& deadProcesses)
{
    for (auto pid : deadProcesses) {
        pm.mProcessMap.erase(pid);
    }
}

void PresentMon_Update(PresentMonData& pm, std::vector<std::shared_ptr<PresentEvent>>& presents, uint64_t perfFreq)
{
    std::string display;
    uint64_t now = GetTickCount64();

    // store the new presents into processes
    for (auto& p : presents)
    {
        AddPresent(pm, *p, now, perfFreq);
    }

    // update all processes
    for (auto& proc : pm.mProcessMap)
    {
        if (!pm.mArgs->mEtlFileName) {
            UpdateProcessInfo_Realtime(proc.second, now, proc.first);
        }
        if (proc.second.mModuleName.empty() ||
            proc.second.mChainMap.empty())
        {
            // don't display empty processes
            continue;
        }
        display += FormatString("%s[%d]:\n", proc.second.mModuleName.c_str(),proc.first);
        for (auto& chain : proc.second.mChainMap)
        {
            double fps = ComputeFps(chain.second, perfFreq);
            double dispFps = ComputeDisplayedFps(chain.second, perfFreq);
            double cpuTime = ComputeCpuFrameTime(chain.second, perfFreq);
            double latency = ComputeLatency(chain.second, perfFreq);
            std::string planeString;
            if (chain.second.mLastPresentMode == PresentMode::Hardware_Composed_Independent_Flip) {
                planeString = FormatString(": Plane %d", chain.second.mLastPlane);
            }
            display += FormatString("\t%016llX (%s): SyncInterval %d | Flags %d | %.2lf ms/frame (%.1lf fps, %.1lf displayed fps, %.2lf ms CPU, %.2lf ms latency) (%s%s)%s\n",
                chain.first, RuntimeToString(chain.second.mRuntime), chain.second.mLastSyncInterval, chain.second.mLastFlags, 1000.0/fps, fps, dispFps, cpuTime * 1000.0, latency * 1000.0,
                PresentModeToString(chain.second.mLastPresentMode),
                planeString.c_str(),
                (now - chain.second.mLastUpdateTicks) > 1000 ? " [STALE]" : "");
        }
    }

    // refresh the console
    SetConsoleText(display.c_str());
}

void PresentMon_Shutdown(PresentMonData& pm)
{
    if (pm.mOutputFile)
    {
        fclose(pm.mOutputFile);
        pm.mOutputFile = nullptr;
    }
    pm.mProcessMap.clear();
}
<commit_msg>bring back out of sequence handling<commit_after>//--------------------------------------------------------------------------------------
// Copyright 2015 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies.  Intel makes no representations about the
// suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//--------------------------------------------------------------------------------------

#include "PresentMon.hpp"
#include "Util.hpp"
#include <algorithm>
#include <numeric>
#include <ctime>
#include <iterator>

#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>

#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "shlwapi.lib")

enum {
    MAX_HISTORY_TIME = 2000,
    MAX_DISPLAYED_HISTORY_TIME = 2000,
    CHAIN_TIMEOUT_THRESHOLD_TICKS = 10000 // 10 sec
};

template <typename Map, typename F>
static void map_erase_if(Map& m, F pred)
{
    typename Map::iterator i = m.begin();
    while ((i = std::find_if(i, m.end(), pred)) != m.end()) {
        m.erase(i++);
    }
}

// linear scan from the back end searching for the insert point
template<class T, class Pred>
static void linear_sorted_insert_from_back(std::deque<T>& v, const T& item, Pred less)
{
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        // (item >= *it) ==> insert after *it
        if (!less(item, *it)) {
            v.insert(it.base(), item);
            return;
        }
    }
    v.push_front(item);
}

static void UpdateProcessInfo_Realtime(ProcessInfo& info, uint64_t now, uint32_t thisPid)
{
    if (now - info.mLastRefreshTicks > 1000) {
        info.mLastRefreshTicks = now;
        char path[MAX_PATH] = "<error>";
        HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, thisPid);
        if (h) {
            GetModuleFileNameExA(h, NULL, path, sizeof(path) - 1);
            std::string name = PathFindFileNameA(path);
            if (name != info.mModuleName) {
                info.mChainMap.clear();
                info.mModuleName = name;
            }
            CloseHandle(h);
        } else {
            info.mChainMap.clear();
        }
    }
    // remove chains without recent updates
    map_erase_if(info.mChainMap, [now](const std::pair<const uint64_t, SwapChainData>& entry) {
        return now - entry.second.mLastUpdateTicks > CHAIN_TIMEOUT_THRESHOLD_TICKS;
    });
}

const char* PresentModeToString(PresentMode mode)
{
    switch (mode) {
    case PresentMode::Hardware_Legacy_Flip: return "Hardware: Legacy Flip";
    case PresentMode::Hardware_Legacy_Copy_To_Front_Buffer: return "Hardware: Legacy Copy to front buffer";
    case PresentMode::Hardware_Direct_Flip: return "Hardware: Direct Flip";
    case PresentMode::Hardware_Independent_Flip: return "Hardware: Independent Flip";
    case PresentMode::Composed_Flip: return "Composed: Flip";
    case PresentMode::Composed_Copy_GPU_GDI: return "Composed: Copy with GPU GDI";
    case PresentMode::Composed_Copy_CPU_GDI: return "Composed: Copy with CPU GDI";
    case PresentMode::Composed_Composition_Atlas: return "Composed: Composition Atlas";
    case PresentMode::Hardware_Composed_Independent_Flip: return "Hardware Composed: Independent Flip";
    default: return "Other";
    }
}

const char* RuntimeToString(Runtime rt)
{
    switch (rt) {
    case Runtime::DXGI: return "DXGI";
    case Runtime::D3D9: return "D3D9";
    default: return "Other";
    }
}

void PruneDeque(std::deque<PresentEvent> &presentHistory, uint64_t perfFreq, uint32_t msTimeDiff) {
    while (!presentHistory.empty() &&
           ((double)(presentHistory.back().QpcTime - presentHistory.front().QpcTime) / perfFreq) * 1000 > msTimeDiff) {
        presentHistory.pop_front();
    }
}

void AddPresent(PresentMonData& pm, PresentEvent& p, uint64_t now, uint64_t perfFreq)
{
    auto& proc = pm.mProcessMap[p.ProcessId];
    if (!proc.mLastRefreshTicks && !pm.mArgs->mEtlFileName) {
        UpdateProcessInfo_Realtime(proc, now, p.ProcessId);
    }

    if (pm.mArgs->mTargetProcessName && strcmp(pm.mArgs->mTargetProcessName, "*") &&
        _stricmp(pm.mArgs->mTargetProcessName, proc.mModuleName.c_str())) {
        // process name does not match
        return;
    }
    if (pm.mArgs->mTargetPid && p.ProcessId != pm.mArgs->mTargetPid) {
        return;
    }

    auto& chain = proc.mChainMap[p.SwapChainAddress];

    if (p.FinalState == PresentResult::Presented)
    {
        // FIXME: need a comment about why "PresentResult::Presented" results can appear
        // out of sequence compared to previously recieved non presented results.
        linear_sorted_insert_from_back(chain.mPresentHistory, p,
            [](const PresentEvent& a, const PresentEvent& b) { return a.QpcTime < b.QpcTime; });
        chain.mDisplayedPresentHistory.push_back(p);

        auto numPresents = chain.mPresentHistory.size();
        for (int i = int(numPresents) - 1; i > 0; --i)
        {
            auto& curr = chain.mPresentHistory[i];
            auto& prev = chain.mPresentHistory[i - 1];
            if (curr.logged) break;
            curr.logged = true;

            double deltaMilliseconds = 1000 * double(curr.QpcTime - prev.QpcTime) / perfFreq;
            double deltaReady = curr.ReadyTime == 0 ? 0.0 : (1000 * double(curr.ReadyTime - curr.QpcTime) / perfFreq);
            double deltaDisplayed = curr.ScreenTime == 0 ? 0.0 : (1000 * double(curr.ScreenTime - curr.QpcTime) / perfFreq);
            double timeTakenMilliseconds = 1000 * double(curr.TimeTaken) / perfFreq;
            fprintf(pm.mOutputFile, "%s,%d,0x%016llX,%s,%.3lf,%.3lf,%d,%d,%s,%.3lf,%.3lf,%d\n",
                proc.mModuleName.c_str(), p.ProcessId, p.SwapChainAddress, RuntimeToString(p.Runtime),
                deltaMilliseconds, timeTakenMilliseconds, curr.SyncInterval, curr.PresentFlags, PresentModeToString(curr.PresentMode),
                deltaReady, deltaDisplayed, curr.FinalState != PresentResult::Discarded);
        }

        PruneDeque(chain.mDisplayedPresentHistory, perfFreq, MAX_DISPLAYED_HISTORY_TIME);
        PruneDeque(chain.mPresentHistory, perfFreq, MAX_HISTORY_TIME);
    } else {
        chain.mPresentHistory.push_back(p);
    }

    chain.mLastUpdateTicks = now;
    chain.mRuntime = p.Runtime;
    chain.mLastSyncInterval = p.SyncInterval;
    chain.mLastFlags = p.PresentFlags;
    chain.mLastPresentMode = p.PresentMode;
    chain.mLastPlane = p.PlaneIndex;
}

static double ComputeFps(const std::deque<PresentEvent>& presentHistory, uint64_t qpcFreq)
{
    if (presentHistory.size() < 2) {
        return 0.0;
    }
    auto start = presentHistory.front().QpcTime;
    auto end = presentHistory.back().QpcTime;
    auto count = presentHistory.size() - 1;

    double deltaT = double(end - start) / qpcFreq;
    return count / deltaT;
}

static double ComputeDisplayedFps(SwapChainData& stats, uint64_t qpcFreq)
{
    return ComputeFps(stats.mDisplayedPresentHistory, qpcFreq);
}

static double ComputeFps(SwapChainData& stats, uint64_t qpcFreq)
{
    return ComputeFps(stats.mPresentHistory, qpcFreq);
}

static double ComputeLatency(SwapChainData& stats, uint64_t qpcFreq)
{
    if (stats.mDisplayedPresentHistory.size() < 2) {
        return 0.0;
    }

    uint64_t totalLatency = std::accumulate(stats.mDisplayedPresentHistory.begin(), stats.mDisplayedPresentHistory.end() - 1, 0ull,
                                   [](uint64_t current, PresentEvent const& e) { return current + e.ScreenTime - e.QpcTime; });
    double average = ((double)(totalLatency) / qpcFreq) / (stats.mDisplayedPresentHistory.size() - 1);
    return average;
}

static double ComputeCpuFrameTime(SwapChainData& stats, uint64_t qpcFreq)
{
    if (stats.mPresentHistory.size() < 2) {
        return 0.0;
    }

    uint64_t timeInPresent = std::accumulate(stats.mPresentHistory.begin(), stats.mPresentHistory.end() - 1, 0ull,
                                   [](uint64_t current, PresentEvent const& e) { return current + e.TimeTaken; });
    uint64_t totalTime = stats.mPresentHistory.back().QpcTime - stats.mPresentHistory.front().QpcTime;

    double timeNotInPresent = double(totalTime - timeInPresent) / qpcFreq;
    return timeNotInPresent / (stats.mPresentHistory.size() - 1);
}

void PresentMon_Init(const PresentMonArgs& args, PresentMonData& pm)
{
    pm.mArgs = &args;

    if (args.mOutputFileName) {
        fopen_s(&pm.mOutputFile, args.mOutputFileName, "w");
    } else if (args.mTargetProcessName) {
        struct tm tm;
        time_t time_now = time(NULL);
        localtime_s(&tm, &time_now);
        std::string date = FormatString("%4d-%02d-%02d-%02d-%02d",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec);
        std::string path;
        if (strchr(args.mTargetProcessName, '*')) {
            path = FormatString("PresentMon-%s.csv", date.c_str());
        } else {
            path = FormatString("PresentMon-%s-%s.csv", args.mTargetProcessName, date.c_str());
        }
        fopen_s(&pm.mOutputFile, path.c_str(), "w");
    }

    if (pm.mOutputFile) {
        fprintf(pm.mOutputFile, "module,pid,chain,runtime,delta,timeTaken,vsync,flags,mode,deltaReady,deltaDisplayed,displayed\n");
    }
}

void PresentMon_UpdateNewProcesses(PresentMonData& pm, std::map<uint32_t, ProcessInfo>& newProcesses)
{
    for (auto processPair : newProcesses) {
        pm.mProcessMap[processPair.first] = processPair.second;
    }
}

void PresentMon_UpdateDeadProcesses(PresentMonData& pm, std::vector<uint32_t>& deadProcesses)
{
    for (auto pid : deadProcesses) {
        pm.mProcessMap.erase(pid);
    }
}

void PresentMon_Update(PresentMonData& pm, std::vector<std::shared_ptr<PresentEvent>>& presents, uint64_t perfFreq)
{
    std::string display;
    uint64_t now = GetTickCount64();

    // store the new presents into processes
    for (auto& p : presents)
    {
        AddPresent(pm, *p, now, perfFreq);
    }

    // update all processes
    for (auto& proc : pm.mProcessMap)
    {
        if (!pm.mArgs->mEtlFileName) {
            UpdateProcessInfo_Realtime(proc.second, now, proc.first);
        }
        if (proc.second.mModuleName.empty() ||
            proc.second.mChainMap.empty())
        {
            // don't display empty processes
            continue;
        }
        display += FormatString("%s[%d]:\n", proc.second.mModuleName.c_str(),proc.first);
        for (auto& chain : proc.second.mChainMap)
        {
            double fps = ComputeFps(chain.second, perfFreq);
            double dispFps = ComputeDisplayedFps(chain.second, perfFreq);
            double cpuTime = ComputeCpuFrameTime(chain.second, perfFreq);
            double latency = ComputeLatency(chain.second, perfFreq);
            std::string planeString;
            if (chain.second.mLastPresentMode == PresentMode::Hardware_Composed_Independent_Flip) {
                planeString = FormatString(": Plane %d", chain.second.mLastPlane);
            }
            display += FormatString("\t%016llX (%s): SyncInterval %d | Flags %d | %.2lf ms/frame (%.1lf fps, %.1lf displayed fps, %.2lf ms CPU, %.2lf ms latency) (%s%s)%s\n",
                chain.first, RuntimeToString(chain.second.mRuntime), chain.second.mLastSyncInterval, chain.second.mLastFlags, 1000.0/fps, fps, dispFps, cpuTime * 1000.0, latency * 1000.0,
                PresentModeToString(chain.second.mLastPresentMode),
                planeString.c_str(),
                (now - chain.second.mLastUpdateTicks) > 1000 ? " [STALE]" : "");
        }
    }

    // refresh the console
    SetConsoleText(display.c_str());
}

void PresentMon_Shutdown(PresentMonData& pm)
{
    if (pm.mOutputFile)
    {
        fclose(pm.mOutputFile);
        pm.mOutputFile = nullptr;
    }
    pm.mProcessMap.clear();
}
<|endoftext|>


<commit_before>#include "SCTPSocket.h"
#include "SocketUtils.h"

#include <netinet/in.h>
#include <cstring>
#include <poll.h>

using namespace NET;

SCTPSocket::SCTPSocket( unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
}

SCTPSocket::SCTPSocket( const std::string& foreignAddress,
                        unsigned short foreignPort,
                        unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
	connect( foreignAddress, foreignPort);
}

SCTPSocket::SCTPSocket( const std::vector<std::string>& foreignAddresses,
                        unsigned short foreignPort,
                        unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
	sockaddr_in *dest = new sockaddr_in[foreignAddresses.size()];
	int i = 0;
	for( std::vector<std::string>::const_iterator it = foreignAddresses.begin(); it != foreignAddresses.end(); ++it)
	{
		fillAddr( (*it), foreignPort, dest[i++]);
	}
	int ret = sctp_connectx( m_socket, reinterpret_cast<sockaddr*>(dest), foreignAddresses.size());
	delete[] dest;
	if(ret < 0)
		throw SocketException("SCTPSocket::SCTPSocket connect failed");
}

SCTPSocket::SCTPSocket( Handle handle)
: InternetSocket( handle.m_sockfd)
{
	if( handle.m_sockfd == 0)
		throw SocketException("Tried to initialize SCTPSocket with invalid Handle");
}

int SCTPSocket::bind( const std::vector<std::string>& localAddresses, unsigned short port /* = 0 */)
{
	sockaddr_in *dest = new sockaddr_in[localAddresses.size()];
	int i = 0;
	for( std::vector<std::string>::const_iterator it = localAddresses.begin(); it != localAddresses.end(); ++it) {
		fillAddr( (*it), port, dest[i++]);
	}
	int ret = sctp_bindx( m_socket, reinterpret_cast<sockaddr*>(dest), localAddresses.size(), SCTP_BINDX_ADD_ADDR);
	delete[] dest;
	if(ret < 0)
		throw SocketException("SCTPSocket::bind bindx failed");
	return ret;
}

int SCTPSocket::state()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::state failed");
	return status.sstat_state;
}

int SCTPSocket::notAckedData()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::notAckedData failed");
	return status.sstat_unackdata;
}

int SCTPSocket::pendingData()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::pendingData failed");
	return status.sstat_penddata;
}

unsigned SCTPSocket::inStreams()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::inStreams failed");
	return status.sstat_instrms;
}

unsigned SCTPSocket::outStreams()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::outStreams failed");
	return status.sstat_outstrms;
}

unsigned SCTPSocket::fragmentationPoint()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::fragmentationPoint failed");
	return status.sstat_fragmentation_point;
}

std::string SCTPSocket::primaryAddress()
{

}

int SCTPSocket::send( const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
                      unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */, switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
{
	int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr, stream, ttl, context);
	if( ret < 0)
		throw SocketException("SCTPSocket::send failed");
	else if (ret < length)
		throw SocketException("Interpreted SCTP false, sent a packet fragement");
	return ret;
}

int SCTPSocket::sendUnordered(  const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
                                unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */,
				switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
{
	int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr + SCTP_UNORDERED, stream, ttl, context);
	if( ret < 0)
		throw SocketException("SCTPSocket::send failed");
	else if (ret < length)
		throw SocketException("Interpreted SCTP false, sent a packet fragement");
	return ret;
}

int SCTPSocket::receive( void* data, int maxLen, unsigned& stream)
{
	struct sctp_sndrcvinfo info;
	int ret;
	if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
		throw SocketException("SCTPSocket::receive failed");
	stream = info.sinfo_stream;
	return ret;
}

int SCTPSocket::receive( void* data, int maxLen, unsigned& stream, receiveFlag& flag)
{
	struct sctp_sndrcvinfo info;
	int ret;
	if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
		throw SocketException("SCTPSocket::receive failed");
	stream = info.sinfo_stream;
	// flag = info.sinfo_flags;
	return ret;
}

int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, unsigned timeout)
{
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);

	if( ret == 0) return 0;
	if( ret < 0)
		throw SocketException("SCTPSocket::receive failed (poll)");

	if( poll.revents & POLLIN || poll.revents & POLLRDHUP) {
		struct sctp_sndrcvinfo info;
		if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
			throw SocketException("SCTPSocket::receive failed (receive)");
		stream = info.sinfo_stream;
		return ret;
	}

	if( poll.revents & POLLRDHUP)
	{
		m_peerDisconnected = true;
		return 0;
	}

	return 0;
}

int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, receiveFlag& flag, unsigned timeout)
{
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);

	if( ret == 0) return 0;
	if( ret < 0) throw SocketException("SCTPSocket::receive failed (poll)");

	if( poll.revents & POLLIN || poll.revents & POLLPRI)
	{
		struct sctp_sndrcvinfo info;
		if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
			throw SocketException("SCTPSocket::receive failed (receive)");
		stream = info.sinfo_stream;
		// flag = info.sinfo_flags;
		return ret;
	}

	if( poll.revents & POLLRDHUP)
	{
		m_peerDisconnected = true;
	}
	return 0;

}

void SCTPSocket::listen( int backlog /* = 0 */)
{
	::listen( m_socket, backlog);
}

SCTPSocket::Handle SCTPSocket::accept()
{
	int ret;
	if( (ret = ::accept( m_socket, 0, 0)) <= 0)
		throw SocketException("SCTPSocket::accept failed");
	return Handle(ret);
}

SCTPSocket::Handle SCTPSocket::timedAccept( unsigned timeout) {
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);
	if( ret == 0)
		return Handle(0);
	if( ret < 0)
		throw SocketException("SCTPSocket::timedAccept failed(poll)");

	if( (ret = ::accept( m_socket, 0, 0)) <= 0)
		throw SocketException("SCTPSocket::timedAccept failed (accept)");
	return Handle(ret);
}

SCTPSocket::Handle SCTPSocket::emptyHandle()
{
	return Handle(0);
}

void SCTPSocket::setInitValues( unsigned numOutStreams, unsigned maxInStreams, unsigned maxAttempts, unsigned maxInitTimeout)
{
	struct sctp_initmsg init;
	std::memset( &init, 0, sizeof(init));
	init.sinit_num_ostreams = numOutStreams;
	init.sinit_max_instreams = maxInStreams;
	init.sinit_max_attempts = maxAttempts;
	init.sinit_max_init_timeo = maxInitTimeout;
	::setsockopt( m_socket, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));
}
<commit_msg>change wrong event name from previous commit<commit_after>#include "SCTPSocket.h"
#include "SocketUtils.h"

#include <netinet/in.h>
#include <cstring>
#include <poll.h>

using namespace NET;

SCTPSocket::SCTPSocket( unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
}

SCTPSocket::SCTPSocket( const std::string& foreignAddress,
                        unsigned short foreignPort,
                        unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
	connect( foreignAddress, foreignPort);
}

SCTPSocket::SCTPSocket( const std::vector<std::string>& foreignAddresses,
                        unsigned short foreignPort,
                        unsigned numOutStreams /* = 10 */,
                        unsigned maxInStreams /* = 65535 */,
                        unsigned maxAttempts /* = 4 */,
                        unsigned maxInitTimeout /* = 0 */)
: InternetSocket( STREAM, IPPROTO_SCTP)
{
	setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
	sockaddr_in *dest = new sockaddr_in[foreignAddresses.size()];
	int i = 0;
	for( std::vector<std::string>::const_iterator it = foreignAddresses.begin(); it != foreignAddresses.end(); ++it)
	{
		fillAddr( (*it), foreignPort, dest[i++]);
	}
	int ret = sctp_connectx( m_socket, reinterpret_cast<sockaddr*>(dest), foreignAddresses.size());
	delete[] dest;
	if(ret < 0)
		throw SocketException("SCTPSocket::SCTPSocket connect failed");
}

SCTPSocket::SCTPSocket( Handle handle)
: InternetSocket( handle.m_sockfd)
{
	if( handle.m_sockfd == 0)
		throw SocketException("Tried to initialize SCTPSocket with invalid Handle");
}

int SCTPSocket::bind( const std::vector<std::string>& localAddresses, unsigned short port /* = 0 */)
{
	sockaddr_in *dest = new sockaddr_in[localAddresses.size()];
	int i = 0;
	for( std::vector<std::string>::const_iterator it = localAddresses.begin(); it != localAddresses.end(); ++it) {
		fillAddr( (*it), port, dest[i++]);
	}
	int ret = sctp_bindx( m_socket, reinterpret_cast<sockaddr*>(dest), localAddresses.size(), SCTP_BINDX_ADD_ADDR);
	delete[] dest;
	if(ret < 0)
		throw SocketException("SCTPSocket::bind bindx failed");
	return ret;
}

int SCTPSocket::state()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::state failed");
	return status.sstat_state;
}

int SCTPSocket::notAckedData()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::notAckedData failed");
	return status.sstat_unackdata;
}

int SCTPSocket::pendingData()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::pendingData failed");
	return status.sstat_penddata;
}

unsigned SCTPSocket::inStreams()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::inStreams failed");
	return status.sstat_instrms;
}

unsigned SCTPSocket::outStreams()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::outStreams failed");
	return status.sstat_outstrms;
}

unsigned SCTPSocket::fragmentationPoint()
{
	struct sctp_status status;
	socklen_t size = sizeof(status);
	if(getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
		throw SocketException("SCTPSocket::fragmentationPoint failed");
	return status.sstat_fragmentation_point;
}

std::string SCTPSocket::primaryAddress()
{

}

int SCTPSocket::send( const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
                      unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */, switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
{
	int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr, stream, ttl, context);
	if( ret < 0)
		throw SocketException("SCTPSocket::send failed");
	else if (ret < length)
		throw SocketException("Interpreted SCTP false, sent a packet fragement");
	return ret;
}

int SCTPSocket::sendUnordered(  const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
                                unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */,
				switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
{
	int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr + SCTP_UNORDERED, stream, ttl, context);
	if( ret < 0)
		throw SocketException("SCTPSocket::send failed");
	else if (ret < length)
		throw SocketException("Interpreted SCTP false, sent a packet fragement");
	return ret;
}

int SCTPSocket::receive( void* data, int maxLen, unsigned& stream)
{
	struct sctp_sndrcvinfo info;
	int ret;
	if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
		throw SocketException("SCTPSocket::receive failed");
	stream = info.sinfo_stream;
	return ret;
}

int SCTPSocket::receive( void* data, int maxLen, unsigned& stream, receiveFlag& flag)
{
	struct sctp_sndrcvinfo info;
	int ret;
	if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
		throw SocketException("SCTPSocket::receive failed");
	stream = info.sinfo_stream;
	// flag = info.sinfo_flags;
	return ret;
}

int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, unsigned timeout)
{
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);

	if( ret == 0) return 0;
	if( ret < 0)
		throw SocketException("SCTPSocket::receive failed (poll)");

	if( poll.revents & POLLIN || poll.revents & POLLRDHUP) {
		struct sctp_sndrcvinfo info;
		if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
			throw SocketException("SCTPSocket::receive failed (receive)");
		stream = info.sinfo_stream;
		return ret;
	}

	if( poll.revents & POLLRDHUP)
	{
		m_peerDisconnected = true;
		return 0;
	}

	return 0;
}

int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, receiveFlag& flag, unsigned timeout)
{
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);

	if( ret == 0) return 0;
	if( ret < 0) throw SocketException("SCTPSocket::receive failed (poll)");

	if( poll.revents & POLLIN || poll.revents & POLLRDHUP)
	{
		struct sctp_sndrcvinfo info;
		if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) <= 0)
			throw SocketException("SCTPSocket::receive failed (receive)");
		stream = info.sinfo_stream;
		// flag = info.sinfo_flags;
		return ret;
	}

	if( poll.revents & POLLRDHUP)
	{
		m_peerDisconnected = true;
	}
	return 0;

}

void SCTPSocket::listen( int backlog /* = 0 */)
{
	::listen( m_socket, backlog);
}

SCTPSocket::Handle SCTPSocket::accept()
{
	int ret;
	if( (ret = ::accept( m_socket, 0, 0)) <= 0)
		throw SocketException("SCTPSocket::accept failed");
	return Handle(ret);
}

SCTPSocket::Handle SCTPSocket::timedAccept( unsigned timeout) {
	struct pollfd poll;
	poll.fd = m_socket;
	poll.events = POLLIN | POLLPRI | POLLRDHUP;

	int ret = ::poll( &poll, 1, timeout);
	if( ret == 0)
		return Handle(0);
	if( ret < 0)
		throw SocketException("SCTPSocket::timedAccept failed(poll)");

	if( (ret = ::accept( m_socket, 0, 0)) <= 0)
		throw SocketException("SCTPSocket::timedAccept failed (accept)");
	return Handle(ret);
}

SCTPSocket::Handle SCTPSocket::emptyHandle()
{
	return Handle(0);
}

void SCTPSocket::setInitValues( unsigned numOutStreams, unsigned maxInStreams, unsigned maxAttempts, unsigned maxInitTimeout)
{
	struct sctp_initmsg init;
	std::memset( &init, 0, sizeof(init));
	init.sinit_num_ostreams = numOutStreams;
	init.sinit_max_instreams = maxInStreams;
	init.sinit_max_attempts = maxAttempts;
	init.sinit_max_init_timeo = maxInitTimeout;
	::setsockopt( m_socket, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));
}
<|endoftext|>


<commit_before>#include "ST7735_LCD.hpp"
#include <LPC17xx.h> //for memory mapped values

//part one
static const uint8_t commands[] = {
		15,							// # of commands in this array
		ST7735_SWRESET, DELAY,		// 1: Software reset with delays
		150, 						//    150 ms delay
		ST7735_SLPOUT, DELAY,		// 2: Out of sleep mode with delay
		255,						// 	  255 ms delay
		ST7735_FRMCTR1, 3,			// 3: frame rate control - normal mode - 3 args
		0x01, 0x2C, 0x2D,			//    Rate = fosc/(1x2+40) * (LINE+2C+2D)
		ST7735_FRMCTR2, 3,			// 4: Frame rate control - idle mode - 3 args
		0x01, 0x2C, 0x2D,			//    Rate = fosc/(1x2+40) * (LINE+2C+2D)
		ST7735_FRMCTR3, 6,			// 5: Frame rate control - partial mode - 3 args
		0x01, 0x2C, 0x2D,			// 	  Dot inversion mode
		0x01, 0x2C, 0x2D,			//	  Line inversion mode
		ST7735_INVCTR, 1,			// 6: Display inversion control - 1 arg - no delay
		0x07,						// 	  no inversion
		ST7735_PWCTR1, 3,			// 7: Power control - 3 args - no delay
		0xA2, 0x02, 0x84,			// 	  0xA2: --- 0x02: -4.6V 0x84: Automode
		ST7735_PWCTR2, 1,			// 8: Power control - 1 arg - no delay
		0xC5,						//    VGH25 = 2.4C VGSEL = -10 VGH = 2 * AVDD
		ST7735_PWCTR3, 2,			// 9: Power control - 2 args - no delay
		0x0A, 0x00,					//    0x0A: opamp current small 0x00: Boost frequency
		ST7735_PWCTR4, 2,			//10: Power control - 2 args - no delay
		0x8A, 0x2A,					//    BCLK/2, Opamp current small & Medium low
		ST7735_PWCTR5, 2, 			//11: Power control - 2 args - no delay
		0x8A, 0xEE,
		ST7735_VMCTR1, 1,			//12: Power control - 1 arg - no delay
		0x0E,
		ST7735_INVOFF, 0, 			//13: Don't invert display - no args - no delay
		ST7735_MADCTL, 1, 			//14: Memory access control (directions) - 1 arg
		0xC8,						//    row addr/col addr, bottom to top refresh
		ST7735_COLMOD, 1,			//15: set color mode - 1 arg - no delay
		0x05						//    16 bit color
};

//part two
static const uint8_t Rcmd2green[] = {
		2,							// 2 commands in the list
		ST7735_CASET, 4,			// 1: Column address set - 4 args - no delay
		0x00, 0x02,					//    XSTART = 0
		0x00, 0x7F+0x02,			//    XEND = 127
		ST7735_RASET, 4,			// 2: Row address set - 4 args - no delay
		0x00, 0x01,					//    XSTART = 0
		0x00, 0x9F+0x01				//    XEND = 159
};

//part 3
static const uint8_t Rcmd3[] = {
		4,							// 4 commands in list
		ST7735_GMCTRP1, 16,			// 1: Magical unicorn dust - 16 args - no delay
		0x02, 0x1c, 0x07, 0x12,
		0x37, 0x32, 0x29, 0x2d,
		0x29, 0x25, 0x2B, 0x39,
		0x00, 0x01, 0x03, 0x10,
		ST7735_GMCTRN1, 16,			// 2: Sparkles and rainbows - 16 args - no delay
	    0x03, 0x1d, 0x07, 0x06,
	    0x2E, 0x2C, 0x29, 0x2D,
	    0x2E, 0x2E, 0x37, 0x3F,
		0x00, 0x00, 0x02, 0x10,
		ST7735_NORON, DELAY,		// 3: Normal display on - no args - with delay
		10, 						//    10 ms delay
		ST7735_DISPON, DELAY,		// 4: Main screen turn on - no args - with delay
		100							//    100 ms delay
};

void ST7735_LCD::initLCD(){
	//SPI set up
	this->setupSPI();
}

//uses SSP1
void ST7735_LCD::setupSPI(){
	//config gpio port to be used for cs
	LPC_PINCON->PINSEL0 &= ~(3 << 12);
	LPC_GPIO0->FIODIR |= (1 << 6); //currently set as output

	//set power to ssp1 and clk
	LPC_SC->PCONP |= (1 << 10);
	LPC_PINCON->PINSEL0 &= ~(3 << 20);
	LPC_PINCON->PINSEL0 |= (1 << 20);

	//select pins to enable to be used as MOSI, MISO, and SCK
	LPC_PINCON->PINSEL0 &= ~( (3 << 14) | (3 << 16) | (3 << 18) );
	LPC_PINCON->PINSEL0 |=  ( (2 << 14) | (2 << 16) | (2 << 18) );

	//set up control registers
	LPC_SSP1->CR0 = 7;
	LPC_SSP1->CR1 = (1 << 1);
	LPC_SSP1->CPSR = 8;
}

void ST7735_LCD::SPI_writecommand(uint8_t c){
	this->SPI_enable();
	this->SPI_exchangeByte(c);
	this->SPI_disable();
}

void ST7735_LCD::commandList(const uint8_t *addr){
	uint8_t numCommands, numArgs;
	uint16_t ms;

	numCommands = addr[0]; //first element contains number of commands to iterate through
	addr++;
	while(numCommands--){
		this->SPI_writecommand((*addr)++);
		numArgs = (*addr)++;
		ms = numArgs & DELAY;
		numArgs &= ~DELAY;
		while(numArgs--)
			this->SPI_writecommand((*addr)++);
	}

	if(ms){
		ms = (*addr)++;
		if(ms == 255) ms = 500;
		vTaskDelay(ms);
	}
}

char ST7735_LCD::SPI_exchangeByte(char out){
	LPC_SSP1->DR = out;
	while(LPC_SSP1->SR & (1 << 4));
	return LPC_SSP1->DR;
}

void ST7735_LCD::SPI_enable(){
	LPC_GPIO0->FIOCLR = (1 << 12);
}

void ST7735_LCD::SPI_disable(){
	LPC_GPIO0->FIOSET = (1 << 12);
}
<commit_msg>adding untested LCD init<commit_after>#include "ST7735_LCD.hpp"
#include <LPC17xx.h> //for memory mapped values

//TODO change SPI names to LCD for clarity/avoid confusion

//part one
static const uint8_t commands[] = {
		15,							// # of commands in this array
		ST7735_SWRESET, DELAY,		// 1: Software reset with delays
		150, 						//    150 ms delay
		ST7735_SLPOUT, DELAY,		// 2: Out of sleep mode with delay
		255,						// 	  255 ms delay
		ST7735_FRMCTR1, 3,			// 3: frame rate control - normal mode - 3 args
		0x01, 0x2C, 0x2D,			//    Rate = fosc/(1x2+40) * (LINE+2C+2D)
		ST7735_FRMCTR2, 3,			// 4: Frame rate control - idle mode - 3 args
		0x01, 0x2C, 0x2D,			//    Rate = fosc/(1x2+40) * (LINE+2C+2D)
		ST7735_FRMCTR3, 6,			// 5: Frame rate control - partial mode - 3 args
		0x01, 0x2C, 0x2D,			// 	  Dot inversion mode
		0x01, 0x2C, 0x2D,			//	  Line inversion mode
		ST7735_INVCTR, 1,			// 6: Display inversion control - 1 arg - no delay
		0x07,						// 	  no inversion
		ST7735_PWCTR1, 3,			// 7: Power control - 3 args - no delay
		0xA2, 0x02, 0x84,			// 	  0xA2: --- 0x02: -4.6V 0x84: Automode
		ST7735_PWCTR2, 1,			// 8: Power control - 1 arg - no delay
		0xC5,						//    VGH25 = 2.4C VGSEL = -10 VGH = 2 * AVDD
		ST7735_PWCTR3, 2,			// 9: Power control - 2 args - no delay
		0x0A, 0x00,					//    0x0A: opamp current small 0x00: Boost frequency
		ST7735_PWCTR4, 2,			//10: Power control - 2 args - no delay
		0x8A, 0x2A,					//    BCLK/2, Opamp current small & Medium low
		ST7735_PWCTR5, 2, 			//11: Power control - 2 args - no delay
		0x8A, 0xEE,
		ST7735_VMCTR1, 1,			//12: Power control - 1 arg - no delay
		0x0E,
		ST7735_INVOFF, 0, 			//13: Don't invert display - no args - no delay
		ST7735_MADCTL, 1, 			//14: Memory access control (directions) - 1 arg
		0xC8,						//    row addr/col addr, bottom to top refresh
		ST7735_COLMOD, 1,			//15: set color mode - 1 arg - no delay
		0x05						//    16 bit color
};

//part two
static const uint8_t Rcmd2green[] = {
		2,							// 2 commands in the list
		ST7735_CASET, 4,			// 1: Column address set - 4 args - no delay
		0x00, 0x02,					//    XSTART = 0
		0x00, 0x7F+0x02,			//    XEND = 127
		ST7735_RASET, 4,			// 2: Row address set - 4 args - no delay
		0x00, 0x01,					//    XSTART = 0
		0x00, 0x9F+0x01				//    XEND = 159
};

//part 3
static const uint8_t Rcmd3[] = {
		4,							// 4 commands in list
		ST7735_GMCTRP1, 16,			// 1: Magical unicorn dust - 16 args - no delay
		0x02, 0x1c, 0x07, 0x12,
		0x37, 0x32, 0x29, 0x2d,
		0x29, 0x25, 0x2B, 0x39,
		0x00, 0x01, 0x03, 0x10,
		ST7735_GMCTRN1, 16,			// 2: Sparkles and rainbows - 16 args - no delay
	    0x03, 0x1d, 0x07, 0x06,
	    0x2E, 0x2C, 0x29, 0x2D,
	    0x2E, 0x2E, 0x37, 0x3F,
		0x00, 0x00, 0x02, 0x10,
		ST7735_NORON, DELAY,		// 3: Normal display on - no args - with delay
		10, 						//    10 ms delay
		ST7735_DISPON, DELAY,		// 4: Main screen turn on - no args - with delay
		100							//    100 ms delay
};

void ST7735_LCD::initLCD(){
	//SPI set up
	this->setupSPI();
	this->commandList(commands);
	this->commandList(Rcmd2green);
	this->commandList(Rcmd3);
}

//uses SSP1
void ST7735_LCD::setupSPI(){
	//config gpio port to be used for cs
	LPC_PINCON->PINSEL0 &= ~(3 << 12);
	LPC_GPIO0->FIODIR |= (1 << 6); //currently set as output

	//set power to ssp1 and clk
	LPC_SC->PCONP |= (1 << 10);
	LPC_PINCON->PINSEL0 &= ~(3 << 20);
	LPC_PINCON->PINSEL0 |= (1 << 20);

	//select pins to enable to be used as MOSI, MISO, and SCK
	LPC_PINCON->PINSEL0 &= ~( (3 << 14) | (3 << 16) | (3 << 18) );
	LPC_PINCON->PINSEL0 |=  ( (2 << 14) | (2 << 16) | (2 << 18) );

	//set up control registers
	LPC_SSP1->CR0 = 7;
	LPC_SSP1->CR1 = (1 << 1);
	LPC_SSP1->CPSR = 8;
}

void ST7735_LCD::SPI_writecommand(uint8_t c){
	this->SPI_enable();
	this->SPI_exchangeByte(c);
	this->SPI_disable();
}

void ST7735_LCD::commandList(const uint8_t *addr){
	uint8_t numCommands, numArgs;
	uint16_t ms;

	numCommands = addr[0]; //first element contains number of commands to iterate through
	addr++;
	while(numCommands--){
		this->SPI_writecommand((*addr)++);
		numArgs = (*addr)++;
		ms = numArgs & DELAY;
		numArgs &= ~DELAY;
		while(numArgs--)
			this->SPI_writecommand((*addr)++);
	}

	if(ms){
		ms = (*addr)++;
		if(ms == 255) ms = 500;
		vTaskDelay(ms);
	}
}

char ST7735_LCD::SPI_exchangeByte(char out){
	LPC_SSP1->DR = out;
	while(LPC_SSP1->SR & (1 << 4));
	return LPC_SSP1->DR;
}

void ST7735_LCD::SPI_enable(){
	LPC_GPIO0->FIOCLR = (1 << 12);
}

void ST7735_LCD::SPI_disable(){
	LPC_GPIO0->FIOSET = (1 << 12);
}
<|endoftext|>


<commit_before>#include "ServerRepo.hpp"
#include "../inanity/data/sqlite.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/PartFile.hpp"
#include "../inanity/StreamReader.hpp"
#include "../inanity/StreamWriter.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

/*

Push:

-> client revision (shortly big)
-> client upper revision (shortly big)
->{
    key size (shortly)
    key data[key size]
    value size (shortly)
    value data[value size]
  }
  0 (shortly)

<- total number of changed unique keys since client revision (shortly big)
<- pre-push revision (shortly big)
<- post-push revision (shortly big)
<-{
    key size (shortly)
    key data[key size]
    value size (shortly)
    value data[value size]
    revision (shortly big)
  }
  0 (shortly)
<- new client revision (shortly big)

*/

ServerRepo::ServerRepo(const char* fileName)
: Repo(fileName)
{
	BEGIN_TRY();

	// check format version
	CheckAppVersion(serverRepoAppVersion);

	// enable exclusive locking mode
	if(sqlite3_exec(*db, "PRAGMA locking_mode = EXCLUSIVE", 0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't enable exclusive locking mode on db", db->Error());

	// create table revs
	if(sqlite3_exec(*db,
		"CREATE TABLE IF NOT EXISTS revs ("
		"rev INTEGER PRIMARY KEY AUTOINCREMENT, "
		"date INTEGER NOT NULL DEFAULT (strftime('%s','now')), "
		"user INTEGER NOT NULL, "
		"key BLOB NOT NULL, "
		"value BLOB NOT NULL)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create table revs", db->Error());
	// create index revs_key_rev
	if(sqlite3_exec(*db,
		"CREATE INDEX IF NOT EXISTS revs_key_rev ON revs (key, rev)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create index revs_key_rev", db->Error());

	// create table users
	if(sqlite3_exec(*db,
		"CREATE TABLE IF NOT EXISTS users ("
		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
		"name TEXT NOT NULL)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create table users", db->Error());
	// create index users_name
	if(sqlite3_exec(*db,
		"CREATE INDEX IF NOT EXISTS users_name ON users (name)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create index users_name", db->Error());

	// create statements
	stmtGetMaxRevision = db->CreateStatement("SELECT MAX(rev) FROM revs");
	stmtWrite = db->CreateStatement("INSERT INTO revs (user, key, value) VALUES (?1, ?2, ?3)");
#define SUBQUERY "SELECT key, MAX(rev) AS maxrev FROM revs GROUP BY key"
	stmtPull = db->CreateStatement(
		"SELECT rev, key, value FROM revs NATURAL JOIN ("
		SUBQUERY
		") WHERE rev > ?1 AND rev <= ?2 AND rev = maxrev ORDER BY rev LIMIT ?3");
	stmtGetWeakRevision = db->CreateStatement(
		"SELECT rev FROM revs NATURAL JOIN ("
		SUBQUERY
		") WHERE rev > ?1 AND rev <= ?2 AND rev = maxrev ORDER BY rev LIMIT 1");
#undef SUBQUERY
	stmtPullTotalSize = db->CreateStatement(
		"SELECT COUNT(DISTINCT key) FROM revs WHERE rev > ?1");
	stmtGetUserId = db->CreateStatement("SELECT id FROM users WHERE name = ?1");
	stmtAddUser = db->CreateStatement("INSERT INTO users (name) VALUES (?1)");

	END_TRY("Can't create server repo");
}

long long ServerRepo::GetMaxRevision()
{
	Data::SqliteQuery query(stmtGetMaxRevision);

	if(stmtGetMaxRevision->Step() != SQLITE_ROW)
		THROW_SECONDARY("Can't get max revision", db->Error());

	return stmtGetMaxRevision->ColumnInt64(0);
}

long long ServerRepo::GetUserId(const String& userName)
{
	BEGIN_TRY();

	// try to find user id
	{
		Data::SqliteQuery query(stmtGetUserId);
		stmtGetUserId->Bind(1, userName);
		switch(stmtGetUserId->Step())
		{
		case SQLITE_ROW:
			return stmtGetUserId->ColumnInt64(0);
		case SQLITE_DONE:
			// no such user
			break;
		default:
			THROW_SECONDARY("Can't find user id", db->Error());
		}
	}

	// add new user
	{
		Data::SqliteQuery query(stmtAddUser);
		stmtAddUser->Bind(1, userName);
		if(stmtAddUser->Step() != SQLITE_DONE)
			THROW("Can't add new user");

		return db->LastInsertRowId();
	}

	END_TRY("Can't get user id");
}

void ServerRepo::WriteManifest(StreamWriter* writer)
{
	BEGIN_TRY();

	// write protocol magic
	writer->Write(protocolMagic, sizeof(protocolMagic));
	// write protocol version
	writer->WriteShortly(protocolVersion);
	// write constraints
	writer->WriteShortly(maxKeySize);
	writer->WriteShortly(maxValueSize);
	writer->WriteShortly(maxPushKeysCount);
	writer->WriteShortly(maxPushTotalSize);
	writer->WriteShortly(maxPullKeysCount);
	writer->WriteShortly(maxPullTotalSize);

	END_TRY("Can't write server repo manifest");
}

bool ServerRepo::Sync(StreamReader* reader, StreamWriter* writer, const String& userName, bool writeAccess)
{
	BEGIN_TRY();

	// get user id
	long long userId = GetUserId(userName);

	// push & pull should be in a one transaction
	Data::SqliteTransaction transaction(db);

	// get initial revision
	long long prePushRevision = GetMaxRevision();

	// read client revision
	long long clientRevision = reader->ReadShortlyBig();
	// read client upper revision
	long long clientUpperRevision = reader->ReadShortlyBig();
	// correct upper revision
	if(clientUpperRevision == 0 || clientUpperRevision > prePushRevision)
		clientUpperRevision = prePushRevision;

	// determine total size of the pull
	{
		Data::SqliteQuery queryPullTotalSize(stmtPullTotalSize);

		stmtPullTotalSize->Bind(1, clientRevision);
		if(stmtPullTotalSize->Step() != SQLITE_ROW)
			THROW("Can't determine total pull size");

		// output total size of pull
		long long pullTotalSize = stmtPullTotalSize->ColumnInt64(0);
		writer->WriteShortlyBig(pullTotalSize);
	}

	//*** push

	void* key = keyBufferFile->GetData();
	void* value = valueBufferFile->GetData();

	size_t totalPushSize = 0;

	// output pre-push revision
	writer->WriteShortlyBig(prePushRevision);

	bool pushedSomething = false;

	// loop for push keys
	for(size_t i = 0; ; ++i)
	{
		// read key size
		size_t keySize = reader->ReadShortly();
		// if it's 0, it's signal of end
		if(!keySize)
			break;

		// if there is no write access right, stop
		if(!writeAccess)
			THROW("Write access denied");

		// check number of keys
		if(i >= (size_t)maxPushKeysCount)
			THROW("Too many keys");

		// check key size
		if(keySize > maxKeySize)
			THROW("Too big key");

		// read key value
		reader->Read(key, keySize);

		// read value
		size_t valueSize = reader->ReadShortly();
		if(valueSize > maxValueSize)
			THROW("Too big value");
		if(valueSize)
			reader->Read(value, valueSize);

		// check total push size
		totalPushSize += valueSize;
		if(totalPushSize > maxPushTotalSize)
			THROW("Too big push total size");

		ptr<File> keyFile = NEW(PartFile(keyBufferFile, key, keySize));

		// do write
		Data::SqliteQuery queryWrite(stmtWrite);
		stmtWrite->Bind(1, userId);
		stmtWrite->Bind(2, keyFile);
		stmtWrite->Bind(3, NEW(PartFile(valueBufferFile, value, valueSize)));
		if(stmtWrite->Step() != SQLITE_DONE)
			THROW_SECONDARY("Can't do write", db->Error());

		pushedSomething = true;
	}

	// ensure request is over
	reader->ReadEnd();

	// output post-push revision
	writer->WriteShortlyBig(GetMaxRevision());

	//*** pull
	Data::SqliteQuery queryPull(stmtPull);

	stmtPull->Bind(1, clientRevision);
	stmtPull->Bind(2, clientUpperRevision);
	stmtPull->Bind(3, maxPullKeysCount);

	long long lastKnownClientRevision = clientRevision;

	size_t totalPullSize = 0;
	bool done = false;
	while(!done)
	{
		switch(stmtPull->Step())
		{
		case SQLITE_ROW:
			// check total pull size
			totalPullSize += stmtPull->ColumnBlobSize(2);
			if(totalPullSize > maxPullTotalSize)
			{
				// stop pull, that's enough
				done = true;
				break;
			}

			// output key
			{
				ptr<File> key = stmtPull->ColumnBlob(1);
				size_t keySize = key->GetSize();
				writer->WriteShortly(keySize);
				writer->Write(key->GetData(), keySize);
			}
			// output value
			{
				ptr<File> value = stmtPull->ColumnBlob(2);
				size_t valueSize = value->GetSize();
				writer->WriteShortly(valueSize);
				writer->Write(value->GetData(), valueSize);
			}
			{
				// output revision
				long long revision = stmtPull->ColumnInt64(0);
				writer->WriteShortlyBig(revision);

				// remember last revision
				lastKnownClientRevision = revision;
			}

			break;

		case SQLITE_DONE:
			// end, no more keys
			done = true;
			break;

		default:
			// some error
			THROW_SECONDARY("Error pulling changes", db->Error());
		}
	}

	// write final zero
	writer->WriteShortly(0);

	// write new client revision
	{
		Data::SqliteQuery query(stmtGetWeakRevision);

		stmtGetWeakRevision->Bind(1, lastKnownClientRevision);
		stmtGetWeakRevision->Bind(2, clientUpperRevision);

		long long newClientRevision;
		switch(stmtGetWeakRevision->Step())
		{
		case SQLITE_ROW:
			newClientRevision = stmtGetWeakRevision->ColumnInt64(0) - 1;
			break;
		case SQLITE_DONE:
			newClientRevision = clientUpperRevision;
			break;
		default:
			THROW_SECONDARY("Error getting new client revision", db->Error());
		}

		writer->WriteShortlyBig(newClientRevision);
	}

	// commit transaction
	transaction.Commit();

	return pushedSomething;

	END_TRY("Can't sync server repo");
}

bool ServerRepo::Watch(StreamReader* reader, StreamWriter* writer)
{
	BEGIN_TRY();

	long long clientRevision = reader->ReadShortlyBig();
	reader->ReadEnd();

	long long maxRevision = GetMaxRevision();

	if(clientRevision < maxRevision)
	{
		writer->WriteShortlyBig(maxRevision);
		return true;
	}

	return false;

	END_TRY("Can't process watch request");
}

void ServerRepo::RespondWatch(StreamWriter* writer)
{
	BEGIN_TRY();

	writer->WriteShortlyBig(GetMaxRevision());

	END_TRY("Can't respond to watch request");
}

END_INANITY_OIL
<commit_msg>server repo fix: get user id in transaction<commit_after>#include "ServerRepo.hpp"
#include "../inanity/data/sqlite.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/PartFile.hpp"
#include "../inanity/StreamReader.hpp"
#include "../inanity/StreamWriter.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

/*

Push:

-> client revision (shortly big)
-> client upper revision (shortly big)
->{
    key size (shortly)
    key data[key size]
    value size (shortly)
    value data[value size]
  }
  0 (shortly)

<- total number of changed unique keys since client revision (shortly big)
<- pre-push revision (shortly big)
<- post-push revision (shortly big)
<-{
    key size (shortly)
    key data[key size]
    value size (shortly)
    value data[value size]
    revision (shortly big)
  }
  0 (shortly)
<- new client revision (shortly big)

*/

ServerRepo::ServerRepo(const char* fileName)
: Repo(fileName)
{
	BEGIN_TRY();

	// check format version
	CheckAppVersion(serverRepoAppVersion);

	// enable exclusive locking mode
	if(sqlite3_exec(*db, "PRAGMA locking_mode = EXCLUSIVE", 0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't enable exclusive locking mode on db", db->Error());

	// create table revs
	if(sqlite3_exec(*db,
		"CREATE TABLE IF NOT EXISTS revs ("
		"rev INTEGER PRIMARY KEY AUTOINCREMENT, "
		"date INTEGER NOT NULL DEFAULT (strftime('%s','now')), "
		"user INTEGER NOT NULL, "
		"key BLOB NOT NULL, "
		"value BLOB NOT NULL)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create table revs", db->Error());
	// create index revs_key_rev
	if(sqlite3_exec(*db,
		"CREATE INDEX IF NOT EXISTS revs_key_rev ON revs (key, rev)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create index revs_key_rev", db->Error());

	// create table users
	if(sqlite3_exec(*db,
		"CREATE TABLE IF NOT EXISTS users ("
		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
		"name TEXT NOT NULL)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create table users", db->Error());
	// create index users_name
	if(sqlite3_exec(*db,
		"CREATE INDEX IF NOT EXISTS users_name ON users (name)",
		0, 0, 0) != SQLITE_OK)
		THROW_SECONDARY("Can't create index users_name", db->Error());

	// create statements
	stmtGetMaxRevision = db->CreateStatement("SELECT MAX(rev) FROM revs");
	stmtWrite = db->CreateStatement("INSERT INTO revs (user, key, value) VALUES (?1, ?2, ?3)");
#define SUBQUERY "SELECT key, MAX(rev) AS maxrev FROM revs GROUP BY key"
	stmtPull = db->CreateStatement(
		"SELECT rev, key, value FROM revs NATURAL JOIN ("
		SUBQUERY
		") WHERE rev > ?1 AND rev <= ?2 AND rev = maxrev ORDER BY rev LIMIT ?3");
	stmtGetWeakRevision = db->CreateStatement(
		"SELECT rev FROM revs NATURAL JOIN ("
		SUBQUERY
		") WHERE rev > ?1 AND rev <= ?2 AND rev = maxrev ORDER BY rev LIMIT 1");
#undef SUBQUERY
	stmtPullTotalSize = db->CreateStatement(
		"SELECT COUNT(DISTINCT key) FROM revs WHERE rev > ?1");
	stmtGetUserId = db->CreateStatement("SELECT id FROM users WHERE name = ?1");
	stmtAddUser = db->CreateStatement("INSERT INTO users (name) VALUES (?1)");

	END_TRY("Can't create server repo");
}

long long ServerRepo::GetMaxRevision()
{
	Data::SqliteQuery query(stmtGetMaxRevision);

	if(stmtGetMaxRevision->Step() != SQLITE_ROW)
		THROW_SECONDARY("Can't get max revision", db->Error());

	return stmtGetMaxRevision->ColumnInt64(0);
}

long long ServerRepo::GetUserId(const String& userName)
{
	BEGIN_TRY();

	// try to find user id
	{
		Data::SqliteQuery query(stmtGetUserId);
		stmtGetUserId->Bind(1, userName);
		switch(stmtGetUserId->Step())
		{
		case SQLITE_ROW:
			return stmtGetUserId->ColumnInt64(0);
		case SQLITE_DONE:
			// no such user
			break;
		default:
			THROW_SECONDARY("Can't find user id", db->Error());
		}
	}

	// add new user
	{
		Data::SqliteQuery query(stmtAddUser);
		stmtAddUser->Bind(1, userName);
		if(stmtAddUser->Step() != SQLITE_DONE)
			THROW("Can't add new user");

		return db->LastInsertRowId();
	}

	END_TRY("Can't get user id");
}

void ServerRepo::WriteManifest(StreamWriter* writer)
{
	BEGIN_TRY();

	// write protocol magic
	writer->Write(protocolMagic, sizeof(protocolMagic));
	// write protocol version
	writer->WriteShortly(protocolVersion);
	// write constraints
	writer->WriteShortly(maxKeySize);
	writer->WriteShortly(maxValueSize);
	writer->WriteShortly(maxPushKeysCount);
	writer->WriteShortly(maxPushTotalSize);
	writer->WriteShortly(maxPullKeysCount);
	writer->WriteShortly(maxPullTotalSize);

	END_TRY("Can't write server repo manifest");
}

bool ServerRepo::Sync(StreamReader* reader, StreamWriter* writer, const String& userName, bool writeAccess)
{
	BEGIN_TRY();

	// push & pull should be in a one transaction
	Data::SqliteTransaction transaction(db);

	// get user id
	long long userId = GetUserId(userName);

	// get initial revision
	long long prePushRevision = GetMaxRevision();

	// read client revision
	long long clientRevision = reader->ReadShortlyBig();
	// read client upper revision
	long long clientUpperRevision = reader->ReadShortlyBig();
	// correct upper revision
	if(clientUpperRevision == 0 || clientUpperRevision > prePushRevision)
		clientUpperRevision = prePushRevision;

	// determine total size of the pull
	{
		Data::SqliteQuery queryPullTotalSize(stmtPullTotalSize);

		stmtPullTotalSize->Bind(1, clientRevision);
		if(stmtPullTotalSize->Step() != SQLITE_ROW)
			THROW("Can't determine total pull size");

		// output total size of pull
		long long pullTotalSize = stmtPullTotalSize->ColumnInt64(0);
		writer->WriteShortlyBig(pullTotalSize);
	}

	//*** push

	void* key = keyBufferFile->GetData();
	void* value = valueBufferFile->GetData();

	size_t totalPushSize = 0;

	// output pre-push revision
	writer->WriteShortlyBig(prePushRevision);

	bool pushedSomething = false;

	// loop for push keys
	for(size_t i = 0; ; ++i)
	{
		// read key size
		size_t keySize = reader->ReadShortly();
		// if it's 0, it's signal of end
		if(!keySize)
			break;

		// if there is no write access right, stop
		if(!writeAccess)
			THROW("Write access denied");

		// check number of keys
		if(i >= (size_t)maxPushKeysCount)
			THROW("Too many keys");

		// check key size
		if(keySize > maxKeySize)
			THROW("Too big key");

		// read key value
		reader->Read(key, keySize);

		// read value
		size_t valueSize = reader->ReadShortly();
		if(valueSize > maxValueSize)
			THROW("Too big value");
		if(valueSize)
			reader->Read(value, valueSize);

		// check total push size
		totalPushSize += valueSize;
		if(totalPushSize > maxPushTotalSize)
			THROW("Too big push total size");

		ptr<File> keyFile = NEW(PartFile(keyBufferFile, key, keySize));

		// do write
		Data::SqliteQuery queryWrite(stmtWrite);
		stmtWrite->Bind(1, userId);
		stmtWrite->Bind(2, keyFile);
		stmtWrite->Bind(3, NEW(PartFile(valueBufferFile, value, valueSize)));
		if(stmtWrite->Step() != SQLITE_DONE)
			THROW_SECONDARY("Can't do write", db->Error());

		pushedSomething = true;
	}

	// ensure request is over
	reader->ReadEnd();

	// output post-push revision
	writer->WriteShortlyBig(GetMaxRevision());

	//*** pull
	Data::SqliteQuery queryPull(stmtPull);

	stmtPull->Bind(1, clientRevision);
	stmtPull->Bind(2, clientUpperRevision);
	stmtPull->Bind(3, maxPullKeysCount);

	long long lastKnownClientRevision = clientRevision;

	size_t totalPullSize = 0;
	bool done = false;
	while(!done)
	{
		switch(stmtPull->Step())
		{
		case SQLITE_ROW:
			// check total pull size
			totalPullSize += stmtPull->ColumnBlobSize(2);
			if(totalPullSize > maxPullTotalSize)
			{
				// stop pull, that's enough
				done = true;
				break;
			}

			// output key
			{
				ptr<File> key = stmtPull->ColumnBlob(1);
				size_t keySize = key->GetSize();
				writer->WriteShortly(keySize);
				writer->Write(key->GetData(), keySize);
			}
			// output value
			{
				ptr<File> value = stmtPull->ColumnBlob(2);
				size_t valueSize = value->GetSize();
				writer->WriteShortly(valueSize);
				writer->Write(value->GetData(), valueSize);
			}
			{
				// output revision
				long long revision = stmtPull->ColumnInt64(0);
				writer->WriteShortlyBig(revision);

				// remember last revision
				lastKnownClientRevision = revision;
			}

			break;

		case SQLITE_DONE:
			// end, no more keys
			done = true;
			break;

		default:
			// some error
			THROW_SECONDARY("Error pulling changes", db->Error());
		}
	}

	// write final zero
	writer->WriteShortly(0);

	// write new client revision
	{
		Data::SqliteQuery query(stmtGetWeakRevision);

		stmtGetWeakRevision->Bind(1, lastKnownClientRevision);
		stmtGetWeakRevision->Bind(2, clientUpperRevision);

		long long newClientRevision;
		switch(stmtGetWeakRevision->Step())
		{
		case SQLITE_ROW:
			newClientRevision = stmtGetWeakRevision->ColumnInt64(0) - 1;
			break;
		case SQLITE_DONE:
			newClientRevision = clientUpperRevision;
			break;
		default:
			THROW_SECONDARY("Error getting new client revision", db->Error());
		}

		writer->WriteShortlyBig(newClientRevision);
	}

	// commit transaction
	transaction.Commit();

	return pushedSomething;

	END_TRY("Can't sync server repo");
}

bool ServerRepo::Watch(StreamReader* reader, StreamWriter* writer)
{
	BEGIN_TRY();

	long long clientRevision = reader->ReadShortlyBig();
	reader->ReadEnd();

	long long maxRevision = GetMaxRevision();

	if(clientRevision < maxRevision)
	{
		writer->WriteShortlyBig(maxRevision);
		return true;
	}

	return false;

	END_TRY("Can't process watch request");
}

void ServerRepo::RespondWatch(StreamWriter* writer)
{
	BEGIN_TRY();

	writer->WriteShortlyBig(GetMaxRevision());

	END_TRY("Can't respond to watch request");
}

END_INANITY_OIL
<|endoftext|>