<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: objmnctl.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 19:19:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_EMBED_VERBATTRIBUTES_HPP_
#include <com/sun/star/embed/VerbAttributes.hpp>
#endif

#include <tools/list.hxx>
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _SXSTRITEM_HXX //autogen
#include <svtools/stritem.hxx>
#endif
#ifndef GCC
#pragma hdrstop
#endif

#include "sfxsids.hrc"
#include "objmnctl.hxx"
#include "dispatch.hxx"
#include "viewsh.hxx"
#include "viewfrm.hxx"
#include "objsh.hxx"

// STATIC DATA -----------------------------------------------------------

SFX_IMPL_MENU_CONTROL(SfxObjectVerbsControl, SfxStringItem);

using namespace com::sun::star;
//--------------------------------------------------------------------

/*
    Ctor; setzt Select-Handler am Menu und traegt Menu
    in seinen Parent ein.
 */

SfxObjectVerbsControl::SfxObjectVerbsControl(USHORT nId, Menu &rMenu, SfxBindings &rBindings)
    : SfxMenuControl( nId, rBindings )
    , pMenu(new PopupMenu)
    , rParent(rMenu)
{
    rMenu.SetPopupMenu(nId, pMenu);
    pMenu->SetSelectHdl(LINK(this, SfxObjectVerbsControl, MenuSelect));
    FillMenu();
}

//--------------------------------------------------------------------

/*
    Fuellt das Menu mit den aktuellen Verben aus der ViewShell.
 */

void SfxObjectVerbsControl::FillMenu()
{
    pMenu->Clear();
    SfxViewShell *pView = GetBindings().GetDispatcher()->GetFrame()->GetViewShell();
    if (pView)
    {
        SfxObjectShell* pDoc = pView->GetObjectShell();
        const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& aVerbs =  pView->GetVerbs();
        if ( aVerbs.getLength() )
        {
            USHORT nId = SID_VERB_START;
            for (USHORT n=0; n<aVerbs.getLength(); n++)
            {
                // check for ReadOnly verbs
                if ( pDoc->IsReadOnly() && !(aVerbs[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
                    continue;

                // check for verbs that shouldn't appear in the menu
                if ( !(aVerbs[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
                    continue;

                DBG_ASSERT(nId <= SID_VERB_END, "Zuviele Verben!");
                if (nId > SID_VERB_END)
                    break;

                pMenu->InsertItem(nId++, aVerbs[n].VerbName);
            }
        }
    }

    rParent.EnableItem( GetId(), (BOOL)pMenu->GetItemCount() );
}

//--------------------------------------------------------------------

/*
    Statusbenachrichtigung;
    fuellt gfs. das Menu mit den aktuellen Verben aus der ViewShell.
    der DocumentShell.
    Ist die Funktionalit"at disabled, wird der entsprechende
    Menueeintrag im Parentmenu disabled, andernfalls wird er enabled.
 */

void SfxObjectVerbsControl::StateChanged( USHORT nSID, SfxItemState eState,
                                          const SfxPoolItem* pState )
{
    rParent.EnableItem(GetId(), SFX_ITEM_AVAILABLE == eState );
    if ( SFX_ITEM_AVAILABLE == eState )
        FillMenu();
}

//--------------------------------------------------------------------

/*
    Select-Handler des Menus;
    das selektierte Verb mit ausgef"uhrt,
 */

IMPL_LINK_INLINE_START( SfxObjectVerbsControl, MenuSelect, Menu *, pMenu )
{
    const USHORT nId = pMenu->GetCurItemId();
    if( nId )
        GetBindings().Execute(nId);
    return 1;
}
IMPL_LINK_INLINE_END( SfxObjectVerbsControl, MenuSelect, Menu *, pMenu )

//--------------------------------------------------------------------

/*
    Dtor; gibt das Menu frei.
 */

SfxObjectVerbsControl::~SfxObjectVerbsControl()
{
    delete pMenu;
}

//--------------------------------------------------------------------

PopupMenu* SfxObjectVerbsControl::GetPopup() const
{
    return pMenu;
}

<commit_msg>INTEGRATION: CWS warnings01 (1.4.66); FILE MERGED 2005/11/28 16:16:38 cd 1.4.66.1: #i55991# Remove warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: objmnctl.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 22:36:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_EMBED_VERBATTRIBUTES_HPP_
#include <com/sun/star/embed/VerbAttributes.hpp>
#endif

#include <tools/list.hxx>
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _SXSTRITEM_HXX //autogen
#include <svtools/stritem.hxx>
#endif
#ifndef GCC
#pragma hdrstop
#endif

#include "sfxsids.hrc"
#include "objmnctl.hxx"
#include "dispatch.hxx"
#include "viewsh.hxx"
#include "viewfrm.hxx"
#include "objsh.hxx"

// STATIC DATA -----------------------------------------------------------

SFX_IMPL_MENU_CONTROL(SfxObjectVerbsControl, SfxStringItem);

using namespace com::sun::star;
//--------------------------------------------------------------------

/*
    Ctor; setzt Select-Handler am Menu und traegt Menu
    in seinen Parent ein.
 */

SfxObjectVerbsControl::SfxObjectVerbsControl(USHORT nSlotId, Menu &rMenu, SfxBindings &rBindings)
    : SfxMenuControl( nSlotId, rBindings )
    , pMenu(new PopupMenu)
    , rParent(rMenu)
{
    rMenu.SetPopupMenu(nSlotId, pMenu);
    pMenu->SetSelectHdl(LINK(this, SfxObjectVerbsControl, MenuSelect));
    FillMenu();
}

//--------------------------------------------------------------------

/*
    Fuellt das Menu mit den aktuellen Verben aus der ViewShell.
 */

void SfxObjectVerbsControl::FillMenu()
{
    pMenu->Clear();
    SfxViewShell *pView = GetBindings().GetDispatcher()->GetFrame()->GetViewShell();
    if (pView)
    {
        SfxObjectShell* pDoc = pView->GetObjectShell();
        const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& aVerbs =  pView->GetVerbs();
        if ( aVerbs.getLength() )
        {
            USHORT nSlotId = SID_VERB_START;
            for (USHORT n=0; n<aVerbs.getLength(); n++)
            {
                // check for ReadOnly verbs
                if ( pDoc->IsReadOnly() && !(aVerbs[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
                    continue;

                // check for verbs that shouldn't appear in the menu
                if ( !(aVerbs[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
                    continue;

                DBG_ASSERT(nSlotId <= SID_VERB_END, "Zuviele Verben!");
                if (nSlotId > SID_VERB_END)
                    break;

                pMenu->InsertItem(nSlotId++, aVerbs[n].VerbName);
            }
        }
    }

    rParent.EnableItem( GetId(), (BOOL)pMenu->GetItemCount() );
}

//--------------------------------------------------------------------

/*
    Statusbenachrichtigung;
    fuellt gfs. das Menu mit den aktuellen Verben aus der ViewShell.
    der DocumentShell.
    Ist die Funktionalit"at disabled, wird der entsprechende
    Menueeintrag im Parentmenu disabled, andernfalls wird er enabled.
 */

void SfxObjectVerbsControl::StateChanged(
    USHORT /*nSID*/,
    SfxItemState eState,
    const SfxPoolItem* /*pState*/ )
{
    rParent.EnableItem(GetId(), SFX_ITEM_AVAILABLE == eState );
    if ( SFX_ITEM_AVAILABLE == eState )
        FillMenu();
}

//--------------------------------------------------------------------

/*
    Select-Handler des Menus;
    das selektierte Verb mit ausgef"uhrt,
 */

IMPL_LINK_INLINE_START( SfxObjectVerbsControl, MenuSelect, Menu *, pSelMenu )
{
    const USHORT nSlotId = pSelMenu->GetCurItemId();
    if( nSlotId )
        GetBindings().Execute(nSlotId);
    return 1;
}
IMPL_LINK_INLINE_END( SfxObjectVerbsControl, MenuSelect, Menu *, pSelMenu )

//--------------------------------------------------------------------

/*
    Dtor; gibt das Menu frei.
 */

SfxObjectVerbsControl::~SfxObjectVerbsControl()
{
    delete pMenu;
}

//--------------------------------------------------------------------

PopupMenu* SfxObjectVerbsControl::GetPopup() const
{
    return pMenu;
}

<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkDICOMQIIOMimeTypes.h"
#include "mitkIOMimeTypes.h"

#include <mitkLogMacros.h>

#include <itkGDCMImageIO.h>
#include <itksys/SystemTools.hxx>

#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcdeftag.h>

namespace mitk
{
  std::vector<CustomMimeType *> MitkDICOMQIIOMimeTypes::Get()
  {
    std::vector<CustomMimeType *> mimeTypes;

    // order matters here (descending rank for mime types)

    mimeTypes.push_back(DICOMSEG_MIMETYPE().Clone());
    //mimeTypes.push_back(DICOMPM_MIMETYPE().Clone());

    return mimeTypes;
  }

  // Mime Types

  //======= Mime Type DICOM SEG =======
  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::MitkDICOMSEGMimeType() : CustomMimeType(DICOMSEG_MIMETYPE_NAME())
  {
    this->AddExtension("dcm");
    this->SetCategory(IOMimeTypes::CATEGORY_IMAGES());
    this->SetComment("DICOM SEG");
  }

  bool MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::AppliesTo(const std::string &path) const
  {
    std::ifstream myfile;
    myfile.open(path, std::ios::binary);
    //    myfile.seekg (128);
    char *buffer = new char[128];
    myfile.read(buffer, 128);
    myfile.read(buffer, 4);
    if (std::string(buffer).compare("DICM") != 0)
    {
      delete[] buffer;
      return false;
    }
    delete[] buffer;

    bool canRead(CustomMimeType::AppliesTo(path));

    // fix for bug 18572
    // Currently this function is called for writing as well as reading, in that case
    // the image information can of course not be read
    // This is a bug, this function should only be called for reading.
    if (!itksys::SystemTools::FileExists(path.c_str()))
    {
      return canRead;
    }
    // end fix for bug 18572

    DcmFileFormat dcmFileFormat;
    OFCondition status = dcmFileFormat.loadFile(path.c_str());

    if (status.bad())
    {
      canRead = false;
    }

    if (!canRead)
    {
      return canRead;
    }

    OFString modality;
    OFString sopClassUID;
    if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good() && dcmFileFormat.getDataset()->findAndGetOFString(DCM_SOPClassUID, sopClassUID).good())
    {
      if (modality.compare("SEG") == 0)
      {//atm we could read SegmentationStorage files. Other storage classes with "SEG" modality, e.g. SurfaceSegmentationStorage (1.2.840.10008.5.1.4.1.1.66.5), are not supported yet.
        if (sopClassUID.compare("1.2.840.10008.5.1.4.1.1.66.4") == 0)
        {
          canRead = true;
        }
        else
        {
          canRead = false;
        }
      }
      else
      {
        canRead = false;
      }
    }

    return canRead;
  }

  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType *MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::Clone() const
  {
    return new MitkDICOMSEGMimeType(*this);
  }

  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType MitkDICOMQIIOMimeTypes::DICOMSEG_MIMETYPE()
  {
    return MitkDICOMSEGMimeType();
  }

  std::string MitkDICOMQIIOMimeTypes::DICOMSEG_MIMETYPE_NAME()
  {
    // create a unique and sensible name for this mime type
    static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.seg";
    return name;
  }

  //======= Mime Type DICOM PM =======
  //...
}
<commit_msg>Fix static initialization<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkDICOMQIIOMimeTypes.h"
#include "mitkIOMimeTypes.h"

#include <mitkLogMacros.h>

#include <itkGDCMImageIO.h>
#include <itksys/SystemTools.hxx>

#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcdeftag.h>

namespace mitk
{
  std::vector<CustomMimeType *> MitkDICOMQIIOMimeTypes::Get()
  {
    std::vector<CustomMimeType *> mimeTypes;

    // order matters here (descending rank for mime types)

    mimeTypes.push_back(DICOMSEG_MIMETYPE().Clone());
    //mimeTypes.push_back(DICOMPM_MIMETYPE().Clone());

    return mimeTypes;
  }

  // Mime Types

  //======= Mime Type DICOM SEG =======
  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::MitkDICOMSEGMimeType() : CustomMimeType(DICOMSEG_MIMETYPE_NAME())
  {
    this->AddExtension("dcm");
    this->SetCategory(IOMimeTypes::CATEGORY_IMAGES());
    this->SetComment("DICOM SEG");
  }

  bool MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::AppliesTo(const std::string &path) const
  {
    std::ifstream myfile;
    myfile.open(path, std::ios::binary);
    //    myfile.seekg (128);
    char *buffer = new char[128];
    myfile.read(buffer, 128);
    myfile.read(buffer, 4);
    if (std::string(buffer).compare("DICM") != 0)
    {
      delete[] buffer;
      return false;
    }
    delete[] buffer;

    bool canRead(CustomMimeType::AppliesTo(path));

    // fix for bug 18572
    // Currently this function is called for writing as well as reading, in that case
    // the image information can of course not be read
    // This is a bug, this function should only be called for reading.
    if (!itksys::SystemTools::FileExists(path.c_str()))
    {
      return canRead;
    }
    // end fix for bug 18572

    DcmFileFormat dcmFileFormat;
    OFCondition status = dcmFileFormat.loadFile(path.c_str());

    if (status.bad())
    {
      canRead = false;
    }

    if (!canRead)
    {
      return canRead;
    }

    OFString modality;
    OFString sopClassUID;
    if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good() && dcmFileFormat.getDataset()->findAndGetOFString(DCM_SOPClassUID, sopClassUID).good())
    {
      if (modality.compare("SEG") == 0)
      {//atm we could read SegmentationStorage files. Other storage classes with "SEG" modality, e.g. SurfaceSegmentationStorage (1.2.840.10008.5.1.4.1.1.66.5), are not supported yet.
        if (sopClassUID.compare("1.2.840.10008.5.1.4.1.1.66.4") == 0)
        {
          canRead = true;
        }
        else
        {
          canRead = false;
        }
      }
      else
      {
        canRead = false;
      }
    }

    return canRead;
  }

  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType *MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType::Clone() const
  {
    return new MitkDICOMSEGMimeType(*this);
  }

  MitkDICOMQIIOMimeTypes::MitkDICOMSEGMimeType MitkDICOMQIIOMimeTypes::DICOMSEG_MIMETYPE()
  {
    return MitkDICOMSEGMimeType();
  }

  std::string MitkDICOMQIIOMimeTypes::DICOMSEG_MIMETYPE_NAME()
  {
    // create a unique and sensible name for this mime type
    return IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.seg";
  }

  //======= Mime Type DICOM PM =======
  //...
}
<|endoftext|>


<commit_before><commit_msg>Scanner.<commit_after><|endoftext|>


<commit_before>#pragma once

#include <map>
#include <memory>

#include "pugixml.hpp"

#include "pin_mesh.hpp"
#include "pin.hpp"
#include "material_lib.hpp"
#include "lattice.hpp"
#include "assembly.hpp"
#include "core.hpp"
#include "plane.hpp"

namespace mocc {
    // The core mesh stores everything needed to represent the physical state
    // of the system. Pin meshes, material library, actual pin types, lattices
    // etc. The CoreMesh is then used to perform complex operations like ray
    // tracing, generation of coarse mesh, etc. A lot of the heavy lifting for
    // input processing happens in the constructor, and the CoreMesh assumes
    // ownership of a lot of the structures used to represent the system.
    class CoreMesh {
    public:
        CoreMesh() {
            // do nothing
            return;
        }

        // Construct a CoreMesh from XML input. This routine is responsible for
        // parsing many of the tags in the XML document: <mesh>, <pin>,
        // <material_lib>, <lattice>, <core>
        CoreMesh( pugi::xml_node &input );

        ~CoreMesh();

        float_t hx() const {
            return hx_;
        }

        float_t hy() const {
            return hy_;
        }

        unsigned int nx() const {
            return nx_;
        }

        unsigned int ny() const {
            return ny_;
        }

        unsigned int nz() const {
            return nz_;
        }

        int n_unique_planes() const {
            return first_unique_.size();
        }

        unsigned int n_reg() const {
            return n_reg_;
        }

        // Given a vector containing two points (Which should be on the boundary
        // of the core mesh), insert points corresponding to intersections of
        // the line formed by those points. The points are added to the vector
        // itself.
        void trace( std::vector<Point2> &p ) const;

        // return a reference to the PinMesh that occupies the space at a point,
        // within a given plane.
        const PinMesh* get_pinmesh( Point2 &p, unsigned int iz,
                int &first_reg) const;

        const Plane& plane( unsigned int iz ) const {
            assert( (0 <= iz) & (iz < planes_.size()) );
            return planes_[iz];
        }

        std::vector<const Pin*>::const_iterator begin_pin() const {
            return core_pins_.cbegin();
        }

        std::vector<const Pin*>::const_iterator end_pin() const {
            return core_pins_.cend();
        }

        // Return a reference to the material library
        const MaterialLib& mat_lib() const {
            return mat_lib_;
        }

        // Return the first FSR index for a given plane
        unsigned int first_reg_plane( unsigned int iz ) const {
            assert( (0 <= iz ) & ( iz<nz_ ) );
            return first_reg_plane_[iz];
        }

        // Return the core boundary conditions
        std::vector<Boundary> boundary() const {
            return core_.boundary();
        }

        std::vector<const Pin*>::const_iterator begin() const {
            return core_pins_.cbegin();
        }

        std::vector<const Pin*>::const_iterator end() const {
            return core_pins_.cend();
        }

        // Return the 1-D index of a position in a lexicographic sense
        unsigned int index_lex( Position pos ) const {
            return pos.x + pos.y*nx_ + pos.z*nx_*ny_;
        }

        // Return a Position, indicating the global position of a pin in the
        // core geometry
        Position pin_position( unsigned int ipin ) const;

    private:
        // Map for storing pin mesh objects indexed by user-specified IDs
        std::map<int, UP_PinMesh_t> pin_meshes_;

        // The material library
        MaterialLib mat_lib_;

        // Map of actual pin objects, indexed by user-specified IDs
        std::map<int, UP_Pin_t> pins_;

        // Map of lattice objects
        std::map<int, Lattice> lattices_;

        // Map of assembly objects
        std::map<int, UP_Assembly_t> assemblies_;

        // Vector of Plane instances. There should be one for each unique planar
        // geometry
        std::vector<Plane> planes_;

        // Vector of references to all pins in the core. This facilitates
        // iteration through the entire problem geometry in a linear fashion.
        // The pins are ordered in the same order that flat source regions are
        // indexed.
        std::vector<const Pin*> core_pins_;

        // Core object (essentially a 2D array of Assemblies)
        Core core_;

        // Total core size in the x dimension
        float_t hx_;

        // Total core size in the y dimension
        float_t hy_;

        // Total core size in the z dimension
        float_t hz_;

        // List of pin boundaries in the x dimension
        VecF x_vec_;

        // List of pin boundaries in the y dimension
        VecF y_vec_;

        // Numbers of pins/planes in each dimension
        unsigned int nx_;
        unsigned int ny_;
        unsigned int nz_;

        // Number of assemblies
        unsigned int nasy_;

        // Total number of FSRs in the entire geometry
        unsigned int n_reg_;
        // Total number of XS regions in the entire geometry
        unsigned int n_xsreg_;

        // List of geometrically-unique planes. Each entry in the list
        // corresponds to the unique plane index that is geometrically valid for
        // the actual plane.
        VecI unique_plane_;

        // Plane index of the first occurance of each geometrically-unique plane
        VecI first_unique_;

        // Index of the first flat source region on each plane
        VecI first_reg_plane_;

        // Vector of Line objects, representing pin boundaries. This greatly
        // simplifies the ray trace.
        std::vector<Line> lines_;
    };

    typedef std::shared_ptr<CoreMesh> SP_CoreMesh_t;
    typedef std::unique_ptr<CoreMesh> UP_CoreMesh_t;
}
<commit_msg>Add n_pin() method to CoreMesh<commit_after>#pragma once

#include <map>
#include <memory>

#include "pugixml.hpp"

#include "pin_mesh.hpp"
#include "pin.hpp"
#include "material_lib.hpp"
#include "lattice.hpp"
#include "assembly.hpp"
#include "core.hpp"
#include "plane.hpp"

namespace mocc {
    // The core mesh stores everything needed to represent the physical state
    // of the system. Pin meshes, material library, actual pin types, lattices
    // etc. The CoreMesh is then used to perform complex operations like ray
    // tracing, generation of coarse mesh, etc. A lot of the heavy lifting for
    // input processing happens in the constructor, and the CoreMesh assumes
    // ownership of a lot of the structures used to represent the system.
    class CoreMesh {
    public:
        CoreMesh() {
            // do nothing
            return;
        }

        // Construct a CoreMesh from XML input. This routine is responsible for
        // parsing many of the tags in the XML document: <mesh>, <pin>,
        // <material_lib>, <lattice>, <core>
        CoreMesh( pugi::xml_node &input );

        ~CoreMesh();

        float_t hx() const {
            return hx_;
        }

        float_t hy() const {
            return hy_;
        }

        unsigned int nx() const {
            return nx_;
        }

        unsigned int ny() const {
            return ny_;
        }

        unsigned int nz() const {
            return nz_;
        }

        unsigned int n_pin() const {
            return nx_*ny_*nz_;
        }

        int n_unique_planes() const {
            return first_unique_.size();
        }

        unsigned int n_reg() const {
            return n_reg_;
        }

        // Given a vector containing two points (Which should be on the boundary
        // of the core mesh), insert points corresponding to intersections of
        // the line formed by those points. The points are added to the vector
        // itself.
        void trace( std::vector<Point2> &p ) const;

        // return a reference to the PinMesh that occupies the space at a point,
        // within a given plane.
        const PinMesh* get_pinmesh( Point2 &p, unsigned int iz,
                int &first_reg) const;

        const Plane& plane( unsigned int iz ) const {
            assert( (0 <= iz) & (iz < planes_.size()) );
            return planes_[iz];
        }

        std::vector<const Pin*>::const_iterator begin_pin() const {
            return core_pins_.cbegin();
        }

        std::vector<const Pin*>::const_iterator end_pin() const {
            return core_pins_.cend();
        }

        // Return a reference to the material library
        const MaterialLib& mat_lib() const {
            return mat_lib_;
        }

        // Return the first FSR index for a given plane
        unsigned int first_reg_plane( unsigned int iz ) const {
            assert( (0 <= iz ) & ( iz<nz_ ) );
            return first_reg_plane_[iz];
        }

        // Return the core boundary conditions
        std::vector<Boundary> boundary() const {
            return core_.boundary();
        }

        std::vector<const Pin*>::const_iterator begin() const {
            return core_pins_.cbegin();
        }

        std::vector<const Pin*>::const_iterator end() const {
            return core_pins_.cend();
        }

        // Return the 1-D index of a position in a lexicographic sense
        unsigned int index_lex( Position pos ) const {
            return pos.x + pos.y*nx_ + pos.z*nx_*ny_;
        }

        // Return a Position, indicating the global position of a pin in the
        // core geometry
        Position pin_position( unsigned int ipin ) const;

    private:
        // Map for storing pin mesh objects indexed by user-specified IDs
        std::map<int, UP_PinMesh_t> pin_meshes_;

        // The material library
        MaterialLib mat_lib_;

        // Map of actual pin objects, indexed by user-specified IDs
        std::map<int, UP_Pin_t> pins_;

        // Map of lattice objects
        std::map<int, Lattice> lattices_;

        // Map of assembly objects
        std::map<int, UP_Assembly_t> assemblies_;

        // Vector of Plane instances. There should be one for each unique planar
        // geometry
        std::vector<Plane> planes_;

        // Vector of references to all pins in the core. This facilitates
        // iteration through the entire problem geometry in a linear fashion.
        // The pins are ordered in the same order that flat source regions are
        // indexed.
        std::vector<const Pin*> core_pins_;

        // Core object (essentially a 2D array of Assemblies)
        Core core_;

        // Total core size in the x dimension
        float_t hx_;

        // Total core size in the y dimension
        float_t hy_;

        // Total core size in the z dimension
        float_t hz_;

        // List of pin boundaries in the x dimension
        VecF x_vec_;

        // List of pin boundaries in the y dimension
        VecF y_vec_;

        // Numbers of pins/planes in each dimension
        unsigned int nx_;
        unsigned int ny_;
        unsigned int nz_;

        // Number of assemblies
        unsigned int nasy_;

        // Total number of FSRs in the entire geometry
        unsigned int n_reg_;
        // Total number of XS regions in the entire geometry
        unsigned int n_xsreg_;

        // List of geometrically-unique planes. Each entry in the list
        // corresponds to the unique plane index that is geometrically valid for
        // the actual plane.
        VecI unique_plane_;

        // Plane index of the first occurance of each geometrically-unique plane
        VecI first_unique_;

        // Index of the first flat source region on each plane
        VecI first_reg_plane_;

        // Vector of Line objects, representing pin boundaries. This greatly
        // simplifies the ray trace.
        std::vector<Line> lines_;
    };

    typedef std::shared_ptr<CoreMesh> SP_CoreMesh_t;
    typedef std::unique_ptr<CoreMesh> UP_CoreMesh_t;
}
<|endoftext|>


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

#include "src/trace_processor/trace_parser.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "perfetto/trace/trace.pb.h"
#include "perfetto/trace/trace_packet.pb.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::Args;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Pointwise;
using ::testing::_;

class FakeStringBlobReader : public BlobReader {
 public:
  FakeStringBlobReader(const std::string& data) : data_(data) {}
  ~FakeStringBlobReader() override {}

  uint32_t Read(uint64_t offset, uint32_t len, uint8_t* dst) override {
    PERFETTO_CHECK(offset <= data_.size());
    uint32_t rsize =
        std::min(static_cast<uint32_t>(data_.size() - offset), len);
    memcpy(dst, data_.c_str() + offset, rsize);
    return rsize;
  }

 private:
  std::string data_;
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD7(InsertSchedSwitch,
               void(uint32_t cpu,
                    uint64_t timestamp,
                    uint32_t prev_pid,
                    uint32_t prev_state,
                    const char* prev_comm,
                    size_t prev_comm_len,
                    uint32_t next_pid));
};

TEST(TraceParser, LoadSingleEvent) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName);
  sched_switch->set_next_pid(100);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName, sizeof(kProcName) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultipleEvents) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultiplePackets) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, RepeatedLoadSinglePacket) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  // Make the chunk size the size of the first packet.
  uint32_t chunk_size = static_cast<uint32_t>(trace.ByteSize());

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, chunk_size);
  parser.ParseNextChunk();

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  parser.ParseNextChunk();
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix failing unittests am: 26189a26e1 am: 9f3fe340f4<commit_after>/*
 * Copyright (C) 2017 The Android Open foo Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/trace_parser.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "perfetto/trace/trace.pb.h"
#include "perfetto/trace/trace_packet.pb.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::Args;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Pointwise;
using ::testing::_;

class FakeStringBlobReader : public BlobReader {
 public:
  FakeStringBlobReader(const std::string& data) : data_(data) {}
  ~FakeStringBlobReader() override {}

  uint32_t Read(uint64_t offset, uint32_t len, uint8_t* dst) override {
    PERFETTO_CHECK(offset <= data_.size());
    uint32_t rsize =
        std::min(static_cast<uint32_t>(data_.size() - offset), len);
    memcpy(dst, data_.c_str() + offset, rsize);
    return rsize;
  }

 private:
  std::string data_;
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD7(PushSchedSwitch,
               void(uint32_t cpu,
                    uint64_t timestamp,
                    uint32_t prev_pid,
                    uint32_t prev_state,
                    const char* prev_comm,
                    size_t prev_comm_len,
                    uint32_t next_pid));
};

TEST(TraceParser, LoadSingleEvent) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName);
  sched_switch->set_next_pid(100);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName, sizeof(kProcName) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultipleEvents) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultiplePackets) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, RepeatedLoadSinglePacket) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  // Make the chunk size the size of the first packet.
  uint32_t chunk_size = static_cast<uint32_t>(trace.ByteSize());

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, chunk_size);
  parser.ParseNextChunk();

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  parser.ParseNextChunk();
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


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

#include <aio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include <functional>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/time.h"
#include "src/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
#define PERFETTO_HAS_SIGNAL_H() 1
#else
#define PERFETTO_HAS_SIGNAL_H() 0
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)
#include <linenoise.h>
#endif

#if PERFETTO_HAS_SIGNAL_H()
#include <signal.h>
#endif

using namespace perfetto;
using namespace perfetto::trace_processor;

namespace {
TraceProcessor* g_tp;

#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)

void SetupLineEditor() {
  linenoiseSetMultiLine(true);
  linenoiseHistorySetMaxLen(1000);
}

void FreeLine(char* line) {
  linenoiseHistoryAdd(line);
  linenoiseFree(line);
}

char* GetLine(const char* prompt) {
  return linenoise(prompt);
}

#else

void SetupLineEditor() {}

void FreeLine(char* line) {
  free(line);
}

char* GetLine(const char* prompt) {
  printf("\r%80s\r%s", "", prompt);
  fflush(stdout);
  char* line = new char[1024];
  if (!fgets(line, 1024 - 1, stdin)) {
    FreeLine(line);
    return nullptr;
  }
  if (strlen(line) > 0)
    line[strlen(line) - 1] = 0;
  return line;
}

#endif

void OnQueryResult(base::TimeNanos t_start, const protos::RawQueryResult& res) {
  if (res.has_error()) {
    PERFETTO_ELOG("SQLite error: %s", res.error().c_str());
    return;
  }
  PERFETTO_CHECK(res.columns_size() == res.column_descriptors_size());

  base::TimeNanos t_end = base::GetWallTimeNs();

  for (int r = 0; r < static_cast<int>(res.num_records()); r++) {
    if (r % 32 == 0) {
      if (r > 0) {
        fprintf(stderr, "...\nType 'q' to stop, Enter for more records: ");
        fflush(stderr);
        char input[32];
        if (!fgets(input, sizeof(input) - 1, stdin))
          exit(0);
        if (input[0] == 'q')
          break;
      }
      for (const auto& col : res.column_descriptors())
        printf("%20s ", col.name().c_str());
      printf("\n");

      for (int i = 0; i < res.columns_size(); i++)
        printf("%20s ", "--------------------");
      printf("\n");
    }

    for (int c = 0; c < res.columns_size(); c++) {
      switch (res.column_descriptors(c).type()) {
        case protos::RawQueryResult_ColumnDesc_Type_STRING:
          printf("%-20.20s ", res.columns(c).string_values(r).c_str());
          break;
        case protos::RawQueryResult_ColumnDesc_Type_DOUBLE:
          printf("%20f ", res.columns(c).double_values(r));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_LONG: {
          auto value = res.columns(c).long_values(r);
          printf((value < 0xffffffll) ? "%20lld " : "%20llx ", value);

          break;
        }
      }
    }
    printf("\n");
  }
  printf("\nQuery executed in %.3f ms\n\n", (t_end - t_start).count() / 1E6);
}

}  // namespace

int main(int argc, char** argv) {
  if (argc < 2) {
    PERFETTO_ELOG("Usage: %s [-d] trace_file.proto", argv[0]);
    return 1;
  }
  const char* trace_file_path = nullptr;
  for (int i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      EnableSQLiteVtableDebugging();
      continue;
    }
    trace_file_path = argv[i];
  }

  // Load the trace file into the trace processor.
  TraceProcessor::Config config;
  config.optimization_mode = OptimizationMode::kMaxBandwidth;
  TraceProcessor tp(config);
  base::ScopedFile fd;
  fd.reset(open(trace_file_path, O_RDONLY));
  PERFETTO_CHECK(fd);

  // Load the trace in chunks using async IO. We create a simple pipeline where,
  // at each iteration, we parse the current chunk and asynchronously start
  // reading the next chunk.

  // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz.
  constexpr size_t kChunkSize = 1024 * 1024;
  struct aiocb cb {};
  cb.aio_nbytes = kChunkSize;
  cb.aio_fildes = *fd;

  // The control block has ownership of the buffer while the read is in-flight.
  cb.aio_buf = new uint8_t[kChunkSize];

  PERFETTO_CHECK(aio_read(&cb) == 0);
  struct aiocb* aio_list[1] = {&cb};

  uint64_t file_size = 0;
  auto t_load_start = base::GetWallTimeMs();
  for (int i = 0;; i++) {
    if (i % 128 == 0)
      fprintf(stderr, "\rLoading trace: %.2f MB\r", file_size / 1E6);

    // Block waiting for the pending read to complete.
    PERFETTO_CHECK(aio_suspend(aio_list, 1, nullptr) == 0);
    auto rsize = aio_return(&cb);
    if (rsize <= 0)
      break;
    file_size += static_cast<uint64_t>(rsize);

    // Take ownership of the completed buffer and enqueue a new async read
    // with a fresh buffer.
    std::unique_ptr<uint8_t[]> buf(
        reinterpret_cast<uint8_t*>(const_cast<void*>(cb.aio_buf)));
    cb.aio_buf = new uint8_t[kChunkSize];
    cb.aio_offset += rsize;
    PERFETTO_CHECK(aio_read(&cb) == 0);

    // Parse the completed buffer while the async read is in-flight.
    tp.Parse(std::move(buf), static_cast<size_t>(rsize));
  }
  tp.NotifyEndOfFile();
  double t_load = (base::GetWallTimeMs() - t_load_start).count() / 1E3;
  double size_mb = file_size / 1E6;
  PERFETTO_ILOG("Trace loaded: %.2f MB (%.1f MB/s)", size_mb, size_mb / t_load);
  g_tp = &tp;

#if PERFETTO_HAS_SIGNAL_H()
  signal(SIGINT, [](int) { g_tp->InterruptQuery(); });
#endif

  SetupLineEditor();

  for (;;) {
    char* line = GetLine("> ");
    if (!line || strcmp(line, "q\n") == 0)
      break;
    if (strcmp(line, "") == 0)
      continue;
    protos::RawQueryArgs query;
    query.set_sql_query(line);
    base::TimeNanos t_start = base::GetWallTimeNs();
    g_tp->ExecuteQuery(query, [t_start](const protos::RawQueryResult& res) {
      OnQueryResult(t_start, res);
    });

    FreeLine(line);
  }

  return 0;
}
<commit_msg>trace_processor: Fix deallocation mismatch<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <aio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include <functional>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/time.h"
#include "src/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
#define PERFETTO_HAS_SIGNAL_H() 1
#else
#define PERFETTO_HAS_SIGNAL_H() 0
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)
#include <linenoise.h>
#endif

#if PERFETTO_HAS_SIGNAL_H()
#include <signal.h>
#endif

using namespace perfetto;
using namespace perfetto::trace_processor;

namespace {
TraceProcessor* g_tp;

#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)

void SetupLineEditor() {
  linenoiseSetMultiLine(true);
  linenoiseHistorySetMaxLen(1000);
}

void FreeLine(char* line) {
  linenoiseHistoryAdd(line);
  linenoiseFree(line);
}

char* GetLine(const char* prompt) {
  return linenoise(prompt);
}

#else

void SetupLineEditor() {}

void FreeLine(char* line) {
  delete[] line;
}

char* GetLine(const char* prompt) {
  printf("\r%80s\r%s", "", prompt);
  fflush(stdout);
  char* line = new char[1024];
  if (!fgets(line, 1024 - 1, stdin)) {
    FreeLine(line);
    return nullptr;
  }
  if (strlen(line) > 0)
    line[strlen(line) - 1] = 0;
  return line;
}

#endif

void OnQueryResult(base::TimeNanos t_start, const protos::RawQueryResult& res) {
  if (res.has_error()) {
    PERFETTO_ELOG("SQLite error: %s", res.error().c_str());
    return;
  }
  PERFETTO_CHECK(res.columns_size() == res.column_descriptors_size());

  base::TimeNanos t_end = base::GetWallTimeNs();

  for (int r = 0; r < static_cast<int>(res.num_records()); r++) {
    if (r % 32 == 0) {
      if (r > 0) {
        fprintf(stderr, "...\nType 'q' to stop, Enter for more records: ");
        fflush(stderr);
        char input[32];
        if (!fgets(input, sizeof(input) - 1, stdin))
          exit(0);
        if (input[0] == 'q')
          break;
      }
      for (const auto& col : res.column_descriptors())
        printf("%20s ", col.name().c_str());
      printf("\n");

      for (int i = 0; i < res.columns_size(); i++)
        printf("%20s ", "--------------------");
      printf("\n");
    }

    for (int c = 0; c < res.columns_size(); c++) {
      switch (res.column_descriptors(c).type()) {
        case protos::RawQueryResult_ColumnDesc_Type_STRING:
          printf("%-20.20s ", res.columns(c).string_values(r).c_str());
          break;
        case protos::RawQueryResult_ColumnDesc_Type_DOUBLE:
          printf("%20f ", res.columns(c).double_values(r));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_LONG: {
          auto value = res.columns(c).long_values(r);
          printf((value < 0xffffffll) ? "%20lld " : "%20llx ", value);

          break;
        }
      }
    }
    printf("\n");
  }
  printf("\nQuery executed in %.3f ms\n\n", (t_end - t_start).count() / 1E6);
}

}  // namespace

int main(int argc, char** argv) {
  if (argc < 2) {
    PERFETTO_ELOG("Usage: %s [-d] trace_file.proto", argv[0]);
    return 1;
  }
  const char* trace_file_path = nullptr;
  for (int i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      EnableSQLiteVtableDebugging();
      continue;
    }
    trace_file_path = argv[i];
  }

  // Load the trace file into the trace processor.
  TraceProcessor::Config config;
  config.optimization_mode = OptimizationMode::kMaxBandwidth;
  TraceProcessor tp(config);
  base::ScopedFile fd;
  fd.reset(open(trace_file_path, O_RDONLY));
  PERFETTO_CHECK(fd);

  // Load the trace in chunks using async IO. We create a simple pipeline where,
  // at each iteration, we parse the current chunk and asynchronously start
  // reading the next chunk.

  // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz.
  constexpr size_t kChunkSize = 1024 * 1024;
  struct aiocb cb {};
  cb.aio_nbytes = kChunkSize;
  cb.aio_fildes = *fd;

  // The control block has ownership of the buffer while the read is in-flight.
  cb.aio_buf = new uint8_t[kChunkSize];

  PERFETTO_CHECK(aio_read(&cb) == 0);
  struct aiocb* aio_list[1] = {&cb};

  uint64_t file_size = 0;
  auto t_load_start = base::GetWallTimeMs();
  for (int i = 0;; i++) {
    if (i % 128 == 0)
      fprintf(stderr, "\rLoading trace: %.2f MB\r", file_size / 1E6);

    // Block waiting for the pending read to complete.
    PERFETTO_CHECK(aio_suspend(aio_list, 1, nullptr) == 0);
    auto rsize = aio_return(&cb);
    if (rsize <= 0)
      break;
    file_size += static_cast<uint64_t>(rsize);

    // Take ownership of the completed buffer and enqueue a new async read
    // with a fresh buffer.
    std::unique_ptr<uint8_t[]> buf(
        reinterpret_cast<uint8_t*>(const_cast<void*>(cb.aio_buf)));
    cb.aio_buf = new uint8_t[kChunkSize];
    cb.aio_offset += rsize;
    PERFETTO_CHECK(aio_read(&cb) == 0);

    // Parse the completed buffer while the async read is in-flight.
    tp.Parse(std::move(buf), static_cast<size_t>(rsize));
  }
  tp.NotifyEndOfFile();
  double t_load = (base::GetWallTimeMs() - t_load_start).count() / 1E3;
  double size_mb = file_size / 1E6;
  PERFETTO_ILOG("Trace loaded: %.2f MB (%.1f MB/s)", size_mb, size_mb / t_load);
  g_tp = &tp;

#if PERFETTO_HAS_SIGNAL_H()
  signal(SIGINT, [](int) { g_tp->InterruptQuery(); });
#endif

  SetupLineEditor();

  for (;;) {
    char* line = GetLine("> ");
    if (!line || strcmp(line, "q\n") == 0)
      break;
    if (strcmp(line, "") == 0)
      continue;
    protos::RawQueryArgs query;
    query.set_sql_query(line);
    base::TimeNanos t_start = base::GetWallTimeNs();
    g_tp->ExecuteQuery(query, [t_start](const protos::RawQueryResult& res) {
      OnQueryResult(t_start, res);
    });

    FreeLine(line);
  }

  return 0;
}
<|endoftext|>


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

#include <map>
#include <random>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_sorter.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::_;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MockFunction;
using ::testing::NiceMock;

class MockTraceParser : public ProtoTraceParser {
 public:
  MockTraceParser(TraceProcessorContext* context) : ProtoTraceParser(context) {}

  MOCK_METHOD4(MOCK_ParseFtracePacket,
               void(uint32_t cpu,
                    int64_t timestamp,
                    const uint8_t* data,
                    size_t length));

  void ParseFtracePacket(uint32_t cpu,
                         int64_t timestamp,
                         TraceSorter::TimestampedTracePiece ttp) override {
    TraceBlobView& tbv = ttp.blob_view;
    MOCK_ParseFtracePacket(cpu, timestamp, tbv.data(), tbv.length());
  }

  MOCK_METHOD3(MOCK_ParseTracePacket,
               void(int64_t ts, const uint8_t* data, size_t length));

  void ParseTracePacket(int64_t ts,
                        TraceSorter::TimestampedTracePiece ttp) override {
    TraceBlobView& tbv = ttp.blob_view;
    MOCK_ParseTracePacket(ts, tbv.data(), tbv.length());
  }
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD1(InternString, StringId(base::StringView view));
};

class TraceSorterTest : public ::testing::Test {
 public:
  TraceSorterTest()
      : test_buffer_(std::unique_ptr<uint8_t[]>(new uint8_t[8]), 0, 8) {
    storage_ = new NiceMock<MockTraceStorage>();
    context_.storage.reset(storage_);
    context_.sorter.reset(new TraceSorter(&context_, 0 /*window_size*/));
    parser_ = new MockTraceParser(&context_);
    context_.parser.reset(parser_);
  }

 protected:
  TraceProcessorContext context_;
  MockTraceParser* parser_;
  NiceMock<MockTraceStorage>* storage_;
  TraceBlobView test_buffer_;
};

TEST_F(TraceSorterTest, TestFtrace) {
  TraceBlobView view = test_buffer_.slice(0, 1);
  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view.data(), 1));
  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view));
  context_.sorter->FinalizeFtraceEventBatch(0);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, TestTracePacket) {
  TraceBlobView view = test_buffer_.slice(0, 1);
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
  context_.sorter->PushTracePacket(1000, std::move(view));
  context_.sorter->FinalizeFtraceEventBatch(1000);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, Ordering) {
  TraceBlobView view_1 = test_buffer_.slice(0, 1);
  TraceBlobView view_2 = test_buffer_.slice(0, 2);
  TraceBlobView view_3 = test_buffer_.slice(0, 3);
  TraceBlobView view_4 = test_buffer_.slice(0, 4);

  InSequence s;

  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));

  context_.sorter->SetWindowSizeNs(200);
  context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
                                   std::move(view_4));
  context_.sorter->FinalizeFtraceEventBatch(2);
  context_.sorter->PushTracePacket(1001, std::move(view_2));
  context_.sorter->PushTracePacket(1100, std::move(view_3));
  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view_1));

  context_.sorter->FinalizeFtraceEventBatch(0);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, SetWindowSize) {
  TraceBlobView view_1 = test_buffer_.slice(0, 1);
  TraceBlobView view_2 = test_buffer_.slice(0, 2);
  TraceBlobView view_3 = test_buffer_.slice(0, 3);
  TraceBlobView view_4 = test_buffer_.slice(0, 4);

  MockFunction<void(std::string check_point_name)> check;

  {
    InSequence s;

    EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
    EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
    EXPECT_CALL(check, Call("1"));
    EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
    EXPECT_CALL(check, Call("2"));
    EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
  }

  context_.sorter->SetWindowSizeNs(200);
  context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
                                   std::move(view_4));
  context_.sorter->FinalizeFtraceEventBatch(2);
  context_.sorter->PushTracePacket(1001, std::move(view_2));
  context_.sorter->PushTracePacket(1100, std::move(view_3));

  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view_1));
  context_.sorter->FinalizeFtraceEventBatch(0);

  // At this point, we should just flush the 1000 and 1001 packets.
  context_.sorter->SetWindowSizeNs(101);

  // Inform the mock about where we are.
  check.Call("1");

  // Now we should flush the 1100 packet.
  context_.sorter->SetWindowSizeNs(99);

  // Inform the mock about where we are.
  check.Call("2");

  // Now we should flush the 1200 packet.
  context_.sorter->ExtractEventsForced();
}

// Simulates a random stream of ftrace events happening on random CPUs.
// Tests that the output of the TraceSorter matches the timestamp order
// (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest, MultiQueueSorting) {
  std::minstd_rand0 rnd_engine(0);
  std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;

  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _))
      .WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
                                             const uint8_t*, size_t) {
        EXPECT_EQ(expectations.begin()->first, timestamp);
        auto& cpus = expectations.begin()->second;
        bool cpu_found = false;
        for (auto it = cpus.begin(); it < cpus.end(); it++) {
          if (*it != cpu)
            continue;
          cpu_found = true;
          cpus.erase(it);
          break;
        }
        if (cpus.empty())
          expectations.erase(expectations.begin());
        EXPECT_TRUE(cpu_found);
      }));

  for (int i = 0; i < 1000; i++) {
    int64_t ts = abs(static_cast<int64_t>(rnd_engine()));
    int num_cpus = rnd_engine() % 3;
    for (int j = 0; j < num_cpus; j++) {
      uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
      expectations[ts].push_back(cpu);
      context_.sorter->PushFtraceEvent(cpu, ts, TraceBlobView(nullptr, 0, 0));
      context_.sorter->FinalizeFtraceEventBatch(cpu);
    }
  }

  context_.sorter->ExtractEventsForced();
  EXPECT_TRUE(expectations.empty());
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix debug dcheck am: 62d21cb470 am: 5fec3e240c am: 6ec5921890 am: 0b9562dbd5<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "src/trace_processor/proto_trace_parser.h"

#include <map>
#include <random>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_sorter.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::_;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MockFunction;
using ::testing::NiceMock;

class MockTraceParser : public ProtoTraceParser {
 public:
  MockTraceParser(TraceProcessorContext* context) : ProtoTraceParser(context) {}

  MOCK_METHOD4(MOCK_ParseFtracePacket,
               void(uint32_t cpu,
                    int64_t timestamp,
                    const uint8_t* data,
                    size_t length));

  void ParseFtracePacket(uint32_t cpu,
                         int64_t timestamp,
                         TraceSorter::TimestampedTracePiece ttp) override {
    TraceBlobView& tbv = ttp.blob_view;
    MOCK_ParseFtracePacket(cpu, timestamp, tbv.data(), tbv.length());
  }

  MOCK_METHOD3(MOCK_ParseTracePacket,
               void(int64_t ts, const uint8_t* data, size_t length));

  void ParseTracePacket(int64_t ts,
                        TraceSorter::TimestampedTracePiece ttp) override {
    TraceBlobView& tbv = ttp.blob_view;
    MOCK_ParseTracePacket(ts, tbv.data(), tbv.length());
  }
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD1(InternString, StringId(base::StringView view));
};

class TraceSorterTest : public ::testing::Test {
 public:
  TraceSorterTest()
      : test_buffer_(std::unique_ptr<uint8_t[]>(new uint8_t[8]), 0, 8) {
    storage_ = new NiceMock<MockTraceStorage>();
    context_.storage.reset(storage_);
    context_.sorter.reset(new TraceSorter(
        &context_, std::numeric_limits<int64_t>::max() /*window_size*/));
    parser_ = new MockTraceParser(&context_);
    context_.parser.reset(parser_);
  }

 protected:
  TraceProcessorContext context_;
  MockTraceParser* parser_;
  NiceMock<MockTraceStorage>* storage_;
  TraceBlobView test_buffer_;
};

TEST_F(TraceSorterTest, TestFtrace) {
  TraceBlobView view = test_buffer_.slice(0, 1);
  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view.data(), 1));
  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view));
  context_.sorter->FinalizeFtraceEventBatch(0);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, TestTracePacket) {
  TraceBlobView view = test_buffer_.slice(0, 1);
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
  context_.sorter->PushTracePacket(1000, std::move(view));
  context_.sorter->FinalizeFtraceEventBatch(1000);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, Ordering) {
  TraceBlobView view_1 = test_buffer_.slice(0, 1);
  TraceBlobView view_2 = test_buffer_.slice(0, 2);
  TraceBlobView view_3 = test_buffer_.slice(0, 3);
  TraceBlobView view_4 = test_buffer_.slice(0, 4);

  InSequence s;

  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
  EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));

  context_.sorter->SetWindowSizeNs(200);
  context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
                                   std::move(view_4));
  context_.sorter->FinalizeFtraceEventBatch(2);
  context_.sorter->PushTracePacket(1001, std::move(view_2));
  context_.sorter->PushTracePacket(1100, std::move(view_3));
  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view_1));

  context_.sorter->FinalizeFtraceEventBatch(0);
  context_.sorter->ExtractEventsForced();
}

TEST_F(TraceSorterTest, SetWindowSize) {
  TraceBlobView view_1 = test_buffer_.slice(0, 1);
  TraceBlobView view_2 = test_buffer_.slice(0, 2);
  TraceBlobView view_3 = test_buffer_.slice(0, 3);
  TraceBlobView view_4 = test_buffer_.slice(0, 4);

  MockFunction<void(std::string check_point_name)> check;

  {
    InSequence s;

    EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
    EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
    EXPECT_CALL(check, Call("1"));
    EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
    EXPECT_CALL(check, Call("2"));
    EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
  }

  context_.sorter->SetWindowSizeNs(200);
  context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
                                   std::move(view_4));
  context_.sorter->FinalizeFtraceEventBatch(2);
  context_.sorter->PushTracePacket(1001, std::move(view_2));
  context_.sorter->PushTracePacket(1100, std::move(view_3));

  context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
                                   std::move(view_1));
  context_.sorter->FinalizeFtraceEventBatch(0);

  // At this point, we should just flush the 1000 and 1001 packets.
  context_.sorter->SetWindowSizeNs(101);

  // Inform the mock about where we are.
  check.Call("1");

  // Now we should flush the 1100 packet.
  context_.sorter->SetWindowSizeNs(99);

  // Inform the mock about where we are.
  check.Call("2");

  // Now we should flush the 1200 packet.
  context_.sorter->ExtractEventsForced();
}

// Simulates a random stream of ftrace events happening on random CPUs.
// Tests that the output of the TraceSorter matches the timestamp order
// (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest, MultiQueueSorting) {
  std::minstd_rand0 rnd_engine(0);
  std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;

  EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _))
      .WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
                                             const uint8_t*, size_t) {
        EXPECT_EQ(expectations.begin()->first, timestamp);
        auto& cpus = expectations.begin()->second;
        bool cpu_found = false;
        for (auto it = cpus.begin(); it < cpus.end(); it++) {
          if (*it != cpu)
            continue;
          cpu_found = true;
          cpus.erase(it);
          break;
        }
        if (cpus.empty())
          expectations.erase(expectations.begin());
        EXPECT_TRUE(cpu_found);
      }));

  for (int i = 0; i < 1000; i++) {
    int64_t ts = abs(static_cast<int64_t>(rnd_engine()));
    int num_cpus = rnd_engine() % 3;
    for (int j = 0; j < num_cpus; j++) {
      uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
      expectations[ts].push_back(cpu);
      context_.sorter->PushFtraceEvent(cpu, ts, TraceBlobView(nullptr, 0, 0));
      context_.sorter->FinalizeFtraceEventBatch(cpu);
    }
  }

  context_.sorter->ExtractEventsForced();
  EXPECT_TRUE(expectations.empty());
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>