UMAP-APPS

This repository contains applications that use the umap library to manage large regions of memory for them.

  • Take a look at our Getting Started guide for all you need to get up and running.

Getting Started

Dependencies

At a minimum, the programs under umap-apps depend cmake 3.5.1 or greater and upon umap being installed.

Follow the instructions for installing umap from the umap repository located here.

Umap-apps Build and Installation

Once the prerequisites are taken care of, the following lines should get you up and running:

$ git clone https://github.com/LLNL/umap-apps.git
$ mkdir build && cd build
$ cmake -DUMAP_INSTALL_PATH="<path to where umap is installed>" ../umap-apps
$ make

By default, umap-apps will build a Release type build and will use the system defined directories for installation. To specify different build types or specify alternate installation paths, see the Advanced Configuration.

Should you wish to also install the applications in their respective installation directories, type:

$ make install

Umap-apps installs files to the lib, include and bin directories of the CMAKE_INSTALL_PREFIX.

Advanced Configuration

Listed below are the umap-specific options which may be used when configuring your build directory with cmake. Some CMake-specific options have also been added to show how to make additional changes to the build configuration.

cmake -DUMAP_INSTALL_PATH="<path to where umap is installed>"

Here is a summary of the configuration options, their default value, and meaning:

Variable Default Meaning
UMAP_INSTALL_PATH not set Location of umap
CFITS_LIBRARY_PATH not set Location of cfitsio library
CFITS_INCLUDE_PATH not set Location of cfitsio include files
CMAKE_CXX_COMPILER not set C++ compiler to use
DCMAKE_CC_COMPILER not set C compiler to use

These arguments are explained in more detail below:

  • UMAP_INSTALL_PATH Location of prerequisite umap installation.
  • CFITS_INCLUDE_PATH and CFITS_LIBRARY_PATH If these are specified, then the applications that use FITS files as the backing store for umap() will be built.

BFS README

## Generate edge list using a R-MAT generator ``` ./rmat_edge_generator/generate_edge_list

-o [out edge list file name (required)]

-s [seed for random number generator; default is 123]

-v [SCALE; The logarithm base two of the number of vertices; default is 17]

-e [#of edges; default is 2^{SCALE} x 16]

-a [initiator parameter A; default is 0.57]

-b [initiator parameter B; default is 0.19]

-c [initiator parameter C; default is 0.19]

-r [if true, scrambles edge IDs; default is true]

-u [if true, generates edges for the both direction; default is true] ```

  • As for the initiator parameters,

see [Graph500, 3.2 Detailed Text Description](https://graph500.org/?page_id=12#sec-3_2) for more details.

#### Generate Graph 500 inputs ` ./generate_edge_list -o /mnt/ssd/edge_list -v 20 -e $((2**20*16)) `` This command generates a edge list file (/mnt/ssd/edge_list) which contains the edges of a SCALE 20 graph. In Graph 500, the number of edges of a graph is #vertives x 16 (16 is called ‘edge factor’).

## Ingest Edge List (construct CSR graph) ` ./ingest_edge_list -g /l/ssd/csr_graph_file /l/ssd/edgelist1 /l/ssd/edgelist2 `

  • Load edge data from files /l/ssd/edgelist1 and /l/ssd/edgelist2 (you can specify an arbitrary number of files).

A CSR graph is constructed in /l/ssd/csr_graph_file. * Each line of input files must be a pair of source and destination vertex IDs (unsigned 64bit number). * This program treats inputs as a directed graph, that is, it does not ingest edges for both directions. * This is a multi-threads (OpenMP) program. You can control the number of threads using the environment variable OMP_NUM_THREADS. * As for real-world datasets, [SNAP Datasets](http://snap.stanford.edu/data/index.html) is popular in the graph processing community. Please note that some datasets in SNAP are a little different. For example, the first line is a comment; you have to delete the line before running this program.

## Run BFS ` ./run_bfs -n \[#of vertices\] -m \[#of edges\] -g \[/path/to/graph_file\] `

  • You can get #of vertices and #of edges by running ingest_edge_list.
  • This is a multi-threads (OpenMP) program.

You can control the number of threads using the environment variable OMP_NUM_THREADS.

API

Class Hierarchy

Full API

Namespaces

Namespace chrono
Namespace std

STL namespace.

Classes and Structs

Template Struct cube_t
Struct Documentation
template <typename _pixel_type>
struct cube_t

Public Types

template<>
using pixel_type = _pixel_type

Public Members

size_t size_x
size_t size_y
size_t size_k
pixel_type *data
Struct options_t
Struct Documentation
struct options_t

Public Members

int iodirect
int usemmap
int initonly
int noinit
uint64_t page_buffer_size
uint64_t num_churn_pages
uint64_t num_load_pages
uint64_t num_churn_threads
uint64_t num_load_reader_threads
uint64_t num_load_writer_threads
char const *fn
uint64_t testduration
Struct rmat_option_t
Struct Documentation
struct rmat_option_t

Public Members

uint64_t seed = {123}
uint64_t vertex_scale = {17}
uint64_t edge_count = {(1ULL << 17) * 16}
double a = {0.57}
double b = {0.19}
double c = {0.19}
bool scramble_id = {true}
bool generate_both_directions = {true}
Struct Cube
Struct Documentation
struct Cube

Public Members

size_t tile_size
size_t cube_size
off_t page_size
vector<utility::umap_fits_file::Tile> tiles
Struct Tile_Dim
Struct Documentation
struct Tile_Dim

Public Members

std::size_t xDim
std::size_t yDim
std::size_t elem_size
Struct Tile_File
Struct Documentation
struct Tile_File

Public Members

int fd
std::string fname
std::size_t tile_start
std::size_t tile_size
Struct umt_optstruct_t
Struct Documentation
struct umt_optstruct_t

Public Members

int initonly
int noinit
int usemmap
int shuffle
long pagesize
uint64_t numpages
uint64_t numthreads
uint64_t bufsize
uint64_t uffdthreads
uint64_t pages_to_access
char const *filename
char const *dirname
Struct vector_t
Struct Documentation
struct vector_t

Public Members

double x_intercept
double x_slope
double y_intercept
double y_slope
Class beta_distribution
Class Documentation
class beta_distribution

Public Functions

beta_distribution(double a, double b)
template <typename rnd_engine>
double operator()(rnd_engine &engine)
Class pageiotest
Class Documentation
class pageiotest

Public Functions

pageiotest(int _ac, char **_av)
~pageiotest(void)
void start(void)
void run(void)
void stop(void)
Class rmat_edge_generator
Nested Relationships
Class Documentation
class rmat_edge_generator

RMAT edge generator, based on Boost Graph’s RMAT generator

Options include scrambling vertices based on a hash funciton, and symmetrizing the list. Generated edges are not sorted. May contain duplicate and self edges.

Public Types

typedef uint64_t vertex_descriptor
typedef std::pair<uint64_t, uint64_t> value_type
typedef value_type edge_type

Public Functions

rmat_edge_generator(uint64_t seed, uint64_t vertex_scale, uint64_t edge_count, double a, double b, double c, double d, bool scramble, bool undirected)

seed used to be 5489

input_iterator_type begin()

Returns the begin of the input iterator.

input_iterator_type end()

Returns the end of the input iterator.

void sanity_max_vertex_id()
uint64_t max_vertex_id()
size_t size()

Protected Functions

edge_type generate_edge()

Generates a new RMAT edge. This function was adapted from the Boost Graph Library.

edge_type generate_edge(std::mt19937 &rng, std::uniform_real_distribution<> &dis)

Protected Attributes

const uint64_t m_seed
std::mt19937 m_rng
std::uniform_real_distribution m_dis
const uint64_t m_vertex_scale
const uint64_t m_edge_count
const bool m_scramble
const bool m_undirected
const double m_rmat_a
const double m_rmat_b
const double m_rmat_c
const double m_rmat_d
class input_iterator_type : public std::iterator<std::input_iterator_tag, edge_type, ptrdiff_t, const edge_type *, const edge_type&>

InputIterator class for rmat_edge_generator.

Public Functions

input_iterator_type(rmat_edge_generator *ptr_rmat, uint64_t count)
const edge_type &operator*() const
input_iterator_type &operator++()
input_iterator_type operator++(int)
edge_type *operator->()
bool is_equal(const input_iterator_type &_x) const

Friends

bool operator==(const input_iterator_type &x, const input_iterator_type &y)

Return true if x and y are both end or not end, or x and y are the same.

bool operator!=(const input_iterator_type &x, const input_iterator_type &y)

Return false if x and y are both end or not end, or x and y are the same.

Class rmat_edge_generator::input_iterator_type
Nested Relationships

This class is a nested type of Class rmat_edge_generator.

Inheritance Relationships
Base Type
  • public std::iterator< std::input_iterator_tag, edge_type, ptrdiff_t, const edge_type *, const edge_type & >
Class Documentation
class input_iterator_type : public std::iterator<std::input_iterator_tag, edge_type, ptrdiff_t, const edge_type *, const edge_type&>

InputIterator class for rmat_edge_generator.

Public Functions

input_iterator_type(rmat_edge_generator *ptr_rmat, uint64_t count)
const edge_type &operator*() const
input_iterator_type &operator++()
input_iterator_type operator++(int)
edge_type *operator->()
bool is_equal(const input_iterator_type &_x) const

Friends

bool operator==(const input_iterator_type &x, const input_iterator_type &y)

Return true if x and y are both end or not end, or x and y are the same.

bool operator!=(const input_iterator_type &x, const input_iterator_type &y)

Return false if x and y are both end or not end, or x and y are the same.

Class CfitsStoreFile
Inheritance Relationships
Base Type
  • public Store
Class Documentation
class CfitsStoreFile : public Store

Public Functions

CfitsStoreFile(Cube *_cube_, size_t _rsize_, size_t _alignsize_)
~CfitsStoreFile()
ssize_t read_from_store(char *buf, size_t nb, off_t off)
ssize_t write_to_store(char *buf, size_t nb, off_t off)

Public Members

void *region
Class Tile
Class Documentation
class Tile

Public Functions

Tile(const std::string &_fn)
ssize_t pread(std::size_t alignment, void *cpy_buf, void *buf, std::size_t nbytes, off_t offset)
Tile_Dim get_Dim()
Template Class vector_iterator
Class Documentation
template <typename pixel_type>
class vector_iterator

Public Types

template<>
using value_type = pixel_type
template<>
using difference_type = ssize_t
template<>
using iterator_category = std::random_access_iterator_tag
template<>
using pointer = value_type *
template<>
using reference = value_type&

Public Functions

vector_iterator(const median::cube_t<pixel_type> &_cube, const vector_t &_vector, const size_t _start_pos)
vector_iterator(const vector_iterator&)
bool operator==(const vector_iterator &other)
bool operator!=(const vector_iterator &other)
difference_type operator-(const vector_iterator &other)
value_type operator*()
vector_iterator &operator++()

Public Static Functions

static vector_iterator create_end(const median::cube_t<pixel_type> &cube, const vector_t &vector)

Functions

Function bfs::init_bfs
Function Documentation
void bfs::init_bfs(const size_t num_vertices, uint16_t *const level, uint64_t *visited_filter)

initialize variables to run BFS

Parameters
  • num_vertices: The number of veritces
  • level: A pointer of level array
  • A: pointer to an bitset for visited filter

Function bfs::run_bfs
Function Documentation
uint16_t bfs::run_bfs(const size_t num_vertices, const uint64_t *const index, const uint64_t *const edges, uint16_t *const level, uint64_t *visited_filter)

BFS kernel. This kernel runs with OpenMP. In order to simplify the implementation of this kernel, some operations are not designed to avoid race conditions as long as they are consistent with the correct status.

Parameters
  • num_vertices: The number of vertices
  • index: A pointer of an index array
  • edges: A pointer of an edges array
  • level: A pointer of level array
  • visited_filter: A pointer of an bitset for visited filter

Function check_edge_list
Function Documentation

Warning

doxygenfunction: Cannot find function “check_edge_list” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function count_level
Function Documentation

Warning

doxygenfunction: Cannot find function “count_level” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function cpu_setcpu
Function Documentation

Warning

doxygenfunction: Cannot find function “cpu_setcpu” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function do_read_modify_write_pages
Function Documentation

Warning

doxygenfunction: Cannot find function “do_read_modify_write_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function do_read_pages(uint64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “do_read_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function do_read_pages(uint64_t, uint64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “do_read_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function do_write_pages(uint64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “do_write_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function do_write_pages(uint64_t, uint64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “do_write_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function find_bfs_root
Function Documentation

Warning

doxygenfunction: Cannot find function “find_bfs_root” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Template Function get_index
Function Documentation
template <typename pixel_type>
ssize_t get_index(const median::cube_t<pixel_type> &cube, const vector_t &vec, const size_t epoch)

Returns an index of a 3D coordinate. vector version.

Function getns(void)
Function Documentation

Warning

doxygenfunction: Cannot find function “getns” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function getns(void)
Function Documentation

Warning

doxygenfunction: Cannot find function “getns” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function getoptions(options_t&, int&, char **)
Function Documentation
void getoptions(options_t&, int&, char **argv)
Function getoptions(options_t&, int&, char **)
Function Documentation
void getoptions(options_t&, int&, char **argv)
Function ingest_edges
Function Documentation

Warning

doxygenfunction: Cannot find function “ingest_edges” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function initdata(uint64_t *, int64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “initdata” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function initdata(uint64_t *, uint64_t)
Function Documentation

Warning

doxygenfunction: Cannot find function “initdata” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function main(int, char **)
Function Documentation

Warning

doxygenfunction: Cannot find function “main” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function map_graph(const size_t, const size_t, const std::string&)
Function Documentation

Warning

doxygenfunction: Cannot find function “map_graph” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function map_graph(const size_t, const size_t, const std::string&)
Function Documentation

Warning

doxygenfunction: Cannot find function “map_graph” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function map_in_file
Function Documentation
void *utility::map_in_file(std::string filename, bool initonly, bool noinit, bool usemmap, uint64_t numbytes)
Template Function median::get_cube_size
Function Documentation
template <typename pixel_type>
size_t median::get_cube_size(const cube_t<pixel_type> &cube)

Return cube size.

Template Function median::get_frame_size
Function Documentation
template <typename pixel_type>
size_t median::get_frame_size(const cube_t<pixel_type> &cube)

Return frame size.

Template Function median::get_index
Function Documentation
template <typename pixel_type>
ssize_t median::get_index(const cube_t<pixel_type> &cube, const size_t x, const size_t y, const size_t k)

Returns an index of a 3D coordinate.

Template Function median::is_nan
Function Documentation
template <typename pixel_type>
bool median::is_nan(const pixel_type value)
Template Function median::reverse_byte_order
Function Documentation
template <typename T>
T median::reverse_byte_order(const T x)

Reverses byte order.

Return
Given value being reversed byte order
Template Parameters
  • T: Type of value; currently only 4 Byte types are supported
Parameters
  • x: Input value

Function parse_options(int, char **, std::string&, std::vector<std::string>&)
Function Documentation

Warning

doxygenfunction: Cannot find function “parse_options” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function parse_options(int, char **, rmat_option_t *, std::string *)
Function Documentation

Warning

doxygenfunction: Cannot find function “parse_options” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function parse_options(int, char **, size_t&, size_t&, std::string&)
Function Documentation

Warning

doxygenfunction: Cannot find function “parse_options” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function parse_options(int, char **, size_t&, size_t&, std::string&, std::string&)
Function Documentation

Warning

doxygenfunction: Cannot find function “parse_options” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function print_stats
Function Documentation

Warning

doxygenfunction: Cannot find function “print_stats” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function print_top_median
Function Documentation

Warning

doxygenfunction: Cannot find function “print_top_median” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function read_modify_write_test
Function Documentation

Warning

doxygenfunction: Cannot find function “read_modify_write_test” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function read_pages
Function Documentation

Warning

doxygenfunction: Cannot find function “read_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function read_test
Function Documentation

Warning

doxygenfunction: Cannot find function “read_test” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function rmat_edge_generator_detail::hash16
Function Documentation
uint16_t rmat_edge_generator_detail::hash16(uint16_t a)
Function rmat_edge_generator_detail::hash32
Function Documentation
uint32_t rmat_edge_generator_detail::hash32(uint32_t a)

Hash functions

Function rmat_edge_generator_detail::hash_nbits
Function Documentation
uint64_t rmat_edge_generator_detail::hash_nbits(uint64_t input, int n)
Function rmat_edge_generator_detail::shifted_n_hash16
Function Documentation
uint64_t rmat_edge_generator_detail::shifted_n_hash16(uint64_t input, int n)
Function rmat_edge_generator_detail::shifted_n_hash32
Function Documentation
uint64_t rmat_edge_generator_detail::shifted_n_hash32(uint64_t input, int n)
Function shoot_vector
Function Documentation

Warning

doxygenfunction: Cannot find function “shoot_vector” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Template Function torben
Function Documentation
template <typename iterator_type>
iterator_type::value_type torben(iterator_type iterator_begin, iterator_type iterator_end)
Function unmap_file
Function Documentation
void utility::unmap_file(bool usemmap, uint64_t numbytes, void *region)
Function usage
Function Documentation
static void utility::usage(char *pname)
Function utility::bitmap_global_pos
Function Documentation
constexpr uint64_t utility::bitmap_global_pos(const uint64_t pos)

examples input 0 ~ 63 -> return 0; input 64 ~ 127 -> return 1;

Function utility::bitmap_local_pos
Function Documentation
constexpr uint64_t utility::bitmap_local_pos(const uint64_t pos)
Function utility::bitmap_size
Function Documentation
constexpr size_t utility::bitmap_size(const size_t size)

examples input 1 ~ 64 -> return 1; input 65 ~ 128 -> return 2

Function utility::create_file
Function Documentation
bool utility::create_file(const std::string &file_name)
Function utility::elapsed_time_sec()
Function Documentation
std::chrono::high_resolution_clock::time_point utility::elapsed_time_sec()
Function utility::elapsed_time_sec(const std::chrono::high_resolution_clock::time_point&)
Function Documentation
double utility::elapsed_time_sec(const std::chrono::high_resolution_clock::time_point &tic)
Function utility::extend_file_size(const int, const size_t)
Function Documentation
bool utility::extend_file_size(const int fd, const size_t file_size)
Function utility::extend_file_size(const std::string&, const size_t)
Function Documentation
bool utility::extend_file_size(const std::string &file_name, const size_t file_size)
Function utility::extend_file_size_manually
Function Documentation
void utility::extend_file_size_manually(const int fd, const ssize_t file_size)
Function utility::get_bit
Function Documentation
bool utility::get_bit(const uint64_t *const bitmap, const uint64_t pos)
Function utility::get_page_size
Function Documentation
ssize_t utility::get_page_size()

Get the page size.

Return
The size of page size. Return -1 for error cases.

Function utility::map_file
Function Documentation
void *utility::map_file(void *const addr, const size_t length, const int protection, const int flags, const int fd, const off_t offset)

Maps a file checking errors.

Return
On success, returns a pointer to the mapped area. On error, nullptr is returned.
Parameters
  • addr: Same as mmap(2)
  • length: Same as mmap(2)
  • protection: Same as mmap(2)
  • flags: Same as mmap(2)
  • fd: Same as mmap(2)
  • offset: Same as mmap(2)

Function utility::map_file_read_mode
Function Documentation
std::pair<int, void *> utility::map_file_read_mode(const std::string &file_name, void *const addr, const size_t length, const off_t offset, const int additional_flags = 0)

Maps a file with read mode.

Return
On Success, returns a pair of the file descriptor of the file and the starting address for the map. On error, retuns a pair of -1 and nullptr.
Parameters
  • file_name: The name of file to be mapped
  • addr: Normally nullptr; if this is not nullptr the kernel takes it as a hint about where to place the mapping
  • length: The length of the map
  • offset: The offset in the file

Function utility::map_file_write_mode
Function Documentation
std::pair<int, void *> utility::map_file_write_mode(const std::string &file_name, void *const addr, const size_t length, const off_t offset, const int additional_flags = 0)

Maps a file with write mode.

Return
On Success, returns a pair of the file descriptor of the file and the starting address for the map. On error, retuns a pair of -1 and nullptr.
Parameters
  • file_name: The name of a file to be mapped
  • addr: Normally nullptr; if this is not nullptr the kernel takes it as a hint about where to place the mapping
  • length: The length of the map
  • offset: The offset in the file

Function utility::map_in_file
Function Documentation
void *utility::map_in_file(std::string filename, bool initonly, bool noinit, bool usemmap, uint64_t numbytes)
Function utility::msync
Function Documentation
void utility::msync(void *const addr, const size_t length)
Function utility::munmap
Function Documentation
void utility::munmap(void *const addr, const size_t length, const bool call_msync)
Function utility::set_bit
Function Documentation
void utility::set_bit(uint64_t *const bitmap, const uint64_t pos)
Function utility::umap_fits_file::operator<<
Function Documentation
std::ostream &utility::umap_fits_file::operator<<(std::ostream &os, utility::umap_fits_file::Tile const &ft)
Function utility::umap_fits_file::PerFits_alloc_cube
Function Documentation
void *utility::umap_fits_file::PerFits_alloc_cube(string name, size_t *BytesPerElement, size_t *xDim, size_t *yDim, size_t *zDim)
Function utility::umap_fits_file::PerFits_free_cube
Function Documentation
void utility::umap_fits_file::PerFits_free_cube(void *region)
Function utility::umt_getoptions
Function Documentation
void utility::umt_getoptions(utility::umt_optstruct_t *testops, int argc, char *argv[])
Function utility::umt_getpagesize
Function Documentation
long utility::umt_getpagesize(void)
Function utility::unmap_file
Function Documentation
void utility::unmap_file(bool usemmap, uint64_t numbytes, void *region)
Function utility::usage
Function Documentation
static void utility::usage(char *pname)
Function validate_level
Function Documentation

Warning

doxygenfunction: Cannot find function “validate_level” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function validatedata
Function Documentation

Warning

doxygenfunction: Cannot find function “validatedata” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function write_pages
Function Documentation

Warning

doxygenfunction: Cannot find function “write_pages” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Function write_test
Function Documentation

Warning

doxygenfunction: Cannot find function “write_test” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variables

Variable bfs::k_infinite_level
Variable Documentation
const uint16_t bfs::k_infinite_level = std::numeric_limits<uint16_t>::max()
Variable correct_median
Variable Documentation

Warning

doxygenvariable: Cannot find variable “correct_median” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable default_num_random_vector
Variable Documentation

Warning

doxygenvariable: Cannot find variable “default_num_random_vector” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable fd
Variable Documentation
int utility::umap_fits_file::CfitsStoreFile::fd
Variable FILENAME
Variable Documentation
char const *utility::FILENAME = "abc"
Variable g_count
Variable Documentation

Warning

doxygenvariable: Cannot find variable “g_count” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable glb_array
Variable Documentation

Warning

doxygenvariable: Cannot find variable “glb_array” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable num_vectors
Variable Documentation

Warning

doxygenvariable: Cannot find variable “num_vectors” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable NUMCHURNPAGES
Variable Documentation

Warning

doxygenvariable: Cannot find variable “NUMCHURNPAGES” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable NUMCHURNTHREADS
Variable Documentation

Warning

doxygenvariable: Cannot find variable “NUMCHURNTHREADS” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable NUMLOADPAGES
Variable Documentation

Warning

doxygenvariable: Cannot find variable “NUMLOADPAGES” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable NUMLOADREADERS
Variable Documentation

Warning

doxygenvariable: Cannot find variable “NUMLOADREADERS” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable NUMLOADWRITERS
Variable Documentation

Warning

doxygenvariable: Cannot find variable “NUMLOADWRITERS” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable options
Variable Documentation
options_t pageiotest::options
Variable options
Variable Documentation
options_t pageiotest::options
Variable page_step
Variable Documentation

Warning

doxygenvariable: Cannot find variable “page_step” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable pages_to_access
Variable Documentation
uint64_t utility::umt_optstruct_t::pages_to_access
Variable pages_to_access
Variable Documentation
uint64_t utility::umt_optstruct_t::pages_to_access
Variable pagesize
Variable Documentation
long pageiotest::pagesize
Variable pagesize
Variable Documentation
long pageiotest::pagesize
Variable shuffled_indexes
Variable Documentation

Warning

doxygenvariable: Cannot find variable “shuffled_indexes” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable shuffled_indexes
Variable Documentation

Warning

doxygenvariable: Cannot find variable “shuffled_indexes” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable sort_ascending
Variable Documentation

Warning

doxygenvariable: Cannot find variable “sort_ascending” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable TESTDURATION
Variable Documentation

Warning

doxygenvariable: Cannot find variable “TESTDURATION” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable tmppagebuf
Variable Documentation

Warning

doxygenvariable: Cannot find variable “tmppagebuf” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Variable usemmap
Variable Documentation
int options_t::usemmap
Variable utility::BUFFERSIZE
Variable Documentation
const uint64_t utility::BUFFERSIZE = 16
Variable utility::DIRNAME
Variable Documentation
char const *utility::DIRNAME = "/mnt/intel/"
Variable utility::FILENAME
Variable Documentation
char const *utility::FILENAME = "abc"
Variable utility::NUMPAGES
Variable Documentation
const uint64_t utility::NUMPAGES = 10000000
Variable utility::NUMTHREADS
Variable Documentation
const uint64_t utility::NUMTHREADS = 2
Variable utility::umap_fits_file::Cubes
Variable Documentation
std::unordered_map<void *, Cube *> utility::umap_fits_file::Cubes
Variable x_intercept
Variable Documentation
double vector_t::x_intercept
Variable x_slope
Variable Documentation
double vector_t::x_slope
Variable y_intercept
Variable Documentation
double vector_t::y_intercept
Variable y_slope
Variable Documentation
double vector_t::y_slope

Defines

Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define _GNU_SOURCE
Define Documentation
_GNU_SOURCE
Define handle_error_en
Define Documentation

Warning

doxygendefine: Cannot find define “handle_error_en” in doxygen xml output for project “umap-apps” from directory: ../doxygen/xml/

Define MEDIAN_CALCULATION_COLUMN_MAJOR
Define Documentation
MEDIAN_CALCULATION_COLUMN_MAJOR

Memo about median calculation x: horizontal dimension of a frame at a certain time point y: vertical dimension of a frame at a certain time point k: time dimension A cube is a set of ‘k’ frames

Typedefs

Typedef pixel_type
Typedef Documentation
template<>
using median::cube_t<_pixel_type>::pixel_type = _pixel_type
Typedef pixel_type
Typedef Documentation
template<>
using median::cube_t<_pixel_type>::pixel_type = _pixel_type

Directories

Directory generator

Parent directory (bfs)

Directory path: bfs/rmat_edge_generator

Directory churn

Directory path: churn

Directory pfbenchmark

Directory path: pfbenchmark

Directory umapcpu

Directory path: umapcpu

Directory umapsort

Directory path: umapsort

Files

File bfs_kernel.hpp

Parent directory (bfs)

Definition (bfs/bfs_kernel.hpp)
Program Listing for File bfs_kernel.hpp

Return to documentation for file (bfs/bfs_kernel.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BFS_BFS_KERNEL_HPP
#define BFS_BFS_KERNEL_HPP

#include <iostream>
#include <limits>

#include "../utility/bitmap.hpp"
#include "../utility/mmap.hpp"

namespace bfs {

static const uint16_t k_infinite_level = std::numeric_limits<uint16_t>::max();

/// \brief initialize variables to run BFS
/// \param num_vertices The number of veritces
/// \param level A pointer of level array
/// \param A pointer to an bitset for visited filter
void init_bfs(const size_t num_vertices, uint16_t *const level, uint64_t *visited_filter) {
  for (size_t i = 0; i < num_vertices; ++i)
    level[i] = k_infinite_level;
  for (size_t i = 0; i < utility::bitmap_size(num_vertices); ++i)
    visited_filter[i] = 0;
}

/// \brief BFS kernel.
/// This kernel runs with OpenMP.
/// In order to simplify the implementation of this kernel,
/// some operations are not designed to avoid race conditions
/// as long as they are consistent with the correct status.
/// \param num_vertices The number of vertices
/// \param index A pointer of an index array
/// \param edges A pointer of an edges array
/// \param level A pointer of level array
/// \param visited_filter A pointer of an bitset for visited filter
uint16_t run_bfs(const size_t num_vertices,
                 const uint64_t *const index,
                 const uint64_t *const edges,
                 uint16_t *const level,
                 uint64_t *visited_filter) {

  uint16_t current_level = 0;
  bool visited_new_vertex = false;

  while (true) { /// BFS main loop

    /// BFS loop for a single level
    /// We assume that the cost of generating threads at every level is negligible
#ifdef _OPENMP
#pragma omp parallel for schedule (dynamic, 1048576)
#endif
    for (uint64_t src = 0; src < num_vertices; ++src) { /// BFS loop for each level
      if (level[src] != current_level) continue;
      for (size_t i = index[src]; i < index[src + 1]; ++i) {
        const uint64_t trg = edges[i];
        if (!utility::get_bit(visited_filter, trg) && level[trg] == k_infinite_level) {
          level[trg] = current_level + 1;
          utility::set_bit(visited_filter, trg);
          visited_new_vertex = true;
        }
      }
    }

    if (!visited_new_vertex) break;

    ++current_level;
    visited_new_vertex = false;
  } /// End of BFS main loop

  return current_level;
}

}
#endif //BFS_BFS_KERNEL_HPP
Includes
  • ../utility/bitmap.hpp
  • ../utility/mmap.hpp
  • iostream
  • limits
Namespaces
File bitmap.hpp

Parent directory (utility)

Definition (utility/bitmap.hpp)
Program Listing for File bitmap.hpp

Return to documentation for file (utility/bitmap.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LIB_UTILITY_BITMAP_HPP
#define LIB_UTILITY_BITMAP_HPP

#include <iostream>

namespace utility
{

/// examples
/// input 1 ~ 64 -> return 1;  input 65 ~ 128 -> return 2
constexpr size_t bitmap_size(const size_t size)
{
  return (size == 0) ? 0 :
         (size - 1ULL) / (sizeof(uint64_t) * 8ULL) + 1ULL;
}

/// examples
/// input 0 ~ 63 -> return 0; input 64 ~ 127 -> return 1;
constexpr uint64_t bitmap_global_pos(const uint64_t pos)
{
  return (pos >> 6ULL);
}

constexpr uint64_t bitmap_local_pos(const uint64_t pos)
{
  return pos & 0x3FULL;
}

bool get_bit(const uint64_t* const bitmap, const uint64_t pos)
{
  return bitmap[bitmap_global_pos(pos)] & (0x1ULL << bitmap_local_pos(pos));
}

void set_bit(uint64_t* const bitmap, const uint64_t pos)
{
  bitmap[bitmap_global_pos(pos)] |= 0x1ULL << bitmap_local_pos(pos);
}

} // namespace utility

#endif //LIB_UTILITY_BITMAP_HPP
Includes
  • iostream
Namespaces
File churn.cpp

Parent directory (churn)

Definition (churn/churn.cpp)
Program Listing for File churn.cpp

Return to documentation for file (churn/churn.cpp)

/*
 * This file is part of UMAP.  For copyright information see the COPYRIGHT file
 * in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*
   The idea is that we have a single "Load Page" and a set
   of N "Churn Pages" as follows:

   +==================================================+
   |                                                  |
   |                Read Load Page(s)                 |
   |                                                  |
   +--------------------------------------------------+
   |                                                  |
   |           Write{/Read} Load Page(s)              |
   |                                                  |
   +--------------------------------------------------+
   |                                                  |
   |               Churn Page #1                      |
   |                                                  |
   +--------------------------------------------------+
   |                                                  |
   |               Churn Page #...                    |
   |                                                  |
   +--------------------------------------------------+
   |                                                  |
   |               Churn Page #N                      |
   |                                                  |
   +==================================================+

   We then have a smaller page_buffer_size that these pages will be faulted
   into and madvised out of via umap().

   The LoadPage will have a set of num_load_reader and num_load_writer threads
   focussed exclusively on making reads and writes to locations constrained to
   the Load Page.

   The the Churn Pages will have num_churn_reader threads performing random
   byte read accesses across all of the Churn Pages effectively causing the
   Load Page to be paged in and out of the smaller Page_Buffer.
*/
#include <iostream>
#include <cassert>
#include <cstdint>
#include <chrono>
#include <thread>
#include <mutex>
#include <vector>
#include <random>
#include <algorithm>
#include <utmpx.h>  // sched_getcpu()
#include <omp.h>

#include "umap/umap.h"
#include "options.h"
#include "../utility/commandline.hpp"
#include "../utility/umap_file.hpp"

uint64_t g_count = 0;
using namespace std;
using namespace chrono;

class pageiotest {
public:
    pageiotest(int _ac, char** _av): time_to_stop{false}, pagesize{utility::umt_getpagesize()} {
        getoptions(options, _ac, _av);

        umt_options.usemmap = options.usemmap;
        umt_options.filename = options.fn;
        umt_options.noinit = options.noinit;
        umt_options.initonly = options.initonly;

        num_rw_load_pages = num_read_load_pages = options.num_load_pages;
        num_churn_pages = options.num_churn_pages;

        base_addr = utility::map_in_file(options.fn, options.initonly,
            options.noinit, options.usemmap,
            (num_churn_pages + num_rw_load_pages + num_read_load_pages) * pagesize);

        if ( base_addr == nullptr ) {
          exit(1);
        }

        assert(base_addr != NULL);

        read_load_pages = base_addr;
        rw_load_pages = (void*)((uint64_t)base_addr + (num_read_load_pages*pagesize));
        churn_pages = (void*)((uint64_t)base_addr + ( (num_read_load_pages + num_rw_load_pages) * pagesize));

        if ( ! options.noinit ) {
            init();
        }

        cout << "Churn Test:\n\t"
            << options.page_buffer_size << " Pages in page buffer\n\t"
            << num_read_load_pages << " Read Load (focus) pages from " << hex << read_load_pages << " - " << (void*)((char*)read_load_pages+((num_read_load_pages*pagesize)-1)) << dec << "\n\t"
            << num_rw_load_pages << " RW Load (focus) pages from " << hex << rw_load_pages << " - " << (void*)((char*)rw_load_pages+((num_rw_load_pages*pagesize)-1)) << dec << "\n\t"
            << options.num_churn_pages << " Churn pages from " << hex << churn_pages << " - " << (void*)((char*)churn_pages+((options.num_churn_pages*pagesize)-1)) << dec << "\n\t"
            << options.num_churn_threads << " Churn threads\n\t"
            << options.num_load_reader_threads << " Load Reader threads\n\t"
            << options.num_load_writer_threads << " Load Writer threads\n\t"
            << options.fn << " Backing file\n\t"
            << options.testduration << " seconds for test duration.\n\n";

        check();
    }

    ~pageiotest( void ) {
        utility::unmap_file(umt_options.usemmap,
            (options.num_churn_pages + num_rw_load_pages
             + num_read_load_pages) * pagesize, base_addr);
    }

    void start( void ) {
        if (options.initonly)
            return;

        for (uint64_t t = 0; t < options.num_load_reader_threads; ++t)
          load_readers.push_back(new thread{&pageiotest::load_read, this, t});

        for (uint64_t t = 0; t < options.num_load_reader_threads; ++t)
          load_rw_readers.push_back(new thread{&pageiotest::load_rw_read, this, t});

        for (uint64_t t = 0; t < options.num_load_writer_threads && t < 1; ++t)
          load_rw_writers.push_back(new thread{&pageiotest::load_rw_write, this});

        for (uint64_t t = 0; t < options.num_churn_threads; ++t)
            churn_readers.push_back(new thread{&pageiotest::churn, this, t});
    }

    void run( void ) {
        if (options.initonly)
            return;

        this_thread::sleep_for(seconds(options.testduration));
    }

    void stop( void ) {
        time_to_stop = true;
        for (auto i : load_readers)
          i->join();
        for (auto i : load_rw_readers)
          i->join();
        for (auto i : load_rw_writers)
          i->join();
        for (auto i : churn_readers)
          i->join();
    }

private:
    bool time_to_stop;
    utility::umt_optstruct_t umt_options;
    options_t options;

    long pagesize;
    void* base_addr;

    void* read_load_pages;
    void* rw_load_pages;
    void* churn_pages;

    vector<thread*> load_readers;
    vector<thread*> load_rw_readers;
    vector<thread*> load_rw_writers;
    vector<thread*> churn_readers;

    uint64_t num_churn_pages;
    uint64_t num_read_load_pages;
    uint64_t num_rw_load_pages;

    void check() {
        cout << "Checking churn load pages\n";
        {
          uint64_t* p = (uint64_t*)churn_pages;
          for (uint64_t i = 0; i < num_churn_pages * (pagesize/sizeof(*p)); i += (pagesize/sizeof(*p)))
              if (p[i] != i) {
                cerr << "check(CHURN): *(uint64_t*)" << &p[i] << "=" << p[i] << " != " << (unsigned long long)i << endl;
                exit(1);
              }
        }
        cout << "Checking read load pages\n";
        {
          uint64_t* p = (uint64_t*)(uint64_t)read_load_pages;
          for (uint64_t i = 0; i < num_read_load_pages * (pagesize/sizeof(*p)); ++i)
              if (p[i] != i) {
                cerr << "check(READER): *(uint64_t*)" << &p[i] << "=" << p[i] << " != " << (unsigned long long)i << endl;
                exit(1);
              }
        }
        cerr << "Check Complete\n";
    }

    void init() {
        cout << "Initializing churn pages\n";
        {
            uint64_t* p = (uint64_t*)churn_pages;
#pragma omp parallel for
            for (uint64_t i = 0; i < num_churn_pages * (pagesize/sizeof(*p)); ++i)
                p[i] = i;
        }

        cout << "Initializing read load pages pages\n";
        {
          uint64_t* p = (uint64_t*)(uint64_t)read_load_pages;
#pragma omp parallel for
          for (uint64_t i = 0; i < num_read_load_pages * (pagesize/sizeof(*p)); ++i)
              p[i] = i;
        }

        cout << "Initializing rw load pages pages\n";
        {
          uint64_t* p = (uint64_t*)(uint64_t)rw_load_pages;
#pragma omp parallel for
          for (uint64_t i = 0; i < num_rw_load_pages * (pagesize/sizeof(*p)); ++i)
              p[i] = i;
        }
        cerr << "Initialization Complete\n";
    }

    mutex lock;

    uint64_t churn( int tnum ) {
        uint64_t cnt = 0;
        uint64_t idx;
        uint64_t* p = (uint64_t*)churn_pages;
        mt19937 gen(tnum);
        uniform_int_distribution<uint64_t> rnd_int(0, ((num_churn_pages*(pagesize/sizeof(*p)))-1));

        while ( !time_to_stop ) {
            idx = rnd_int(gen);
            if (p[idx] != idx) {
                lock.lock();
                cerr << hex << "churn()    " << p[idx] << " != " << idx << " at address " << &p[idx] << endl;
                lock.unlock();
                break;
            }
        }
        return cnt;
    }

    void load_read(int tnum) {
        uint64_t* p = (uint64_t*)read_load_pages;
        tnum = tnum + 2048;
        mt19937 gen(tnum);
        uniform_int_distribution<uint64_t> rnd_int(0, ((num_read_load_pages*(pagesize/sizeof(*p)))-1));

        while ( !time_to_stop ) {
            uint64_t idx = rnd_int(gen);

            if (p[idx] != idx) {
                lock.lock();
                cerr << "load_read  *(uint64_t*)" << &p[idx] << "=" << p[idx] << " != " << idx << endl;
                lock.unlock();
                break;
            }
        }
    }

    // Have a reader going nuts on the write page for fun. No data validation since the writer is changing it from underneath us.
    void load_rw_read(int tnum) {
        uint64_t* p = (uint64_t*)rw_load_pages;
        tnum = tnum + tnum * 53;
        mt19937 gen(tnum);
        uniform_int_distribution<uint64_t> rnd_int(0, ((num_rw_load_pages*(pagesize/sizeof(*p)))-1));

        while ( !time_to_stop ) {
            uint64_t idx = rnd_int(gen);
            g_count += p[idx];
        }
    }

    void load_rw_write() {
        uint64_t cnt = 0;
        uint64_t* p = (uint64_t*)((uint64_t)rw_load_pages);
        const int num_entries = num_rw_load_pages * pagesize/sizeof(*p);

        omp_set_num_threads(options.num_load_writer_threads);

        while ( !time_to_stop ) {
            uint64_t cnt_base = cnt;

#pragma omp parallel for
            for (int i = 0; i < num_entries; ++i) {
                p[i] = cnt_base + i;
            }

#pragma omp parallel for
            for (int i = 0; i < num_entries; ++i) {
                if (p[i] != (cnt_base + i)) {
#pragma omp critical
                    {
                        lock.lock();
                        cerr << "load_rw_write *(uint64_t*)" << &p[i] << "=" << p[i] << " != " << (cnt_base+i) << ": (" << cnt_base << "+" << i << "=" << (cnt_base+i) << ") - " << p[i] << " = " << ((cnt_base+i)-p[i]) << endl;
                        if (i != 0)
                            cerr << "load_rw_write *(uint64_t*)" << &p[0] << "=" << p[0] << " ,  " << (cnt_base+0) << ": (" << cnt_base << "+" << 0 << "=" << (cnt_base+0) << ") - " << p[0] << " = " << ((cnt_base+0)-p[0]) << endl;
                        lock.unlock();
                    }
                    exit(1);
                }
            }

            cnt += pagesize/sizeof(*p);
        }
    }
};

int main(int argc, char **argv)
{
    pageiotest test{argc, argv};

    test.start();
    test.run();
    test.stop();

    return 0;
}
Includes
Namespaces
Variables
File commandline.hpp

Parent directory (utility)

Definition (utility/commandline.hpp)
Program Listing for File commandline.hpp

Return to documentation for file (utility/commandline.hpp)

/*
 * This file is part of UMAP.  For copyright information see the COPYRIGHT file
 * in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT. This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _COMMANDLING_HPP
#define _COMMANDLING_HPP

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <stdint.h>
#include <iostream>     // cout/cerr
#include <unistd.h>     // getopt()
#include <getopt.h>     // duh...
#include "umap/umap.h"

namespace utility {
typedef struct {
  int initonly;       // Just perform initialization, then quit
  int noinit;         // Init already done, so skip it
  int usemmap;
  int shuffle;

  long pagesize;
  uint64_t numpages;
  uint64_t numthreads;
  uint64_t bufsize;
  uint64_t uffdthreads;
  uint64_t pages_to_access;  // 0 (default) - access all pages
  char const* filename; // file name or basename
  char const* dirname; // dir name or basename
} umt_optstruct_t;

static char const* DIRNAME = "/mnt/intel/";
static char const* FILENAME = "abc";
const uint64_t NUMPAGES = 10000000;
const uint64_t NUMTHREADS = 2;
const uint64_t BUFFERSIZE = 16;

using namespace std;

static void usage(char* pname)
{
  cerr
  << "Usage: " << pname << " [--initonly] [--noinit] [--directio]"
  <<                       " [--usemmap] [-p #] [-t #] [-b #] [-f name]\n\n"
  << " --help                 - This message\n"
  << " --initonly             - Initialize file, then stop\n"
  << " --noinit               - Use previously initialized file\n"
  << " --usemmap              - Use mmap instead of umap\n"
  << " --shuffle              - Shuffle memory accesses (instead of sequential access)\n"
  << " -p # of pages          - default: " << NUMPAGES << endl
  << " -t # of threads        - default: " << NUMTHREADS << endl
  << " -u # of uffd threads   - default: " << umap_cfg_get_uffdthreads() << " worker threads\n"
  << " -b # page buffer size  - default: " << umap_cfg_get_bufsize() << " Pages\n"
  << " -a # pages to access   - default: 0 - access all pages\n"
  << " -f [file name]         - backing file name.  Or file basename if multiple files\n"
  << " -d [directory name]    - backing directory name.  Or dir basename if multiple dirs\n"
  << " -P # page size         - default: " << umap_cfg_get_pagesize() << endl;
  exit(1);
}

void umt_getoptions(utility::umt_optstruct_t* testops, int argc, char *argv[])
{
  int c;
  char *pname = argv[0];

  testops->initonly = 0;
  testops->noinit = 0;
  testops->usemmap = 0;
  testops->shuffle = 0;
  testops->pages_to_access = 0;
  testops->numpages = NUMPAGES;
  testops->numthreads = NUMTHREADS;
  testops->bufsize = umap_cfg_get_bufsize();
  testops->uffdthreads = umap_cfg_get_uffdthreads();
  testops->filename = FILENAME;
  testops->dirname = DIRNAME;
  testops->pagesize = umap_cfg_get_pagesize();

  while (1) {
    int option_index = 0;
    static struct option long_options[] = {
      {"initonly",  no_argument,  &testops->initonly, 1 },
      {"noinit",    no_argument,  &testops->noinit,   1 },
      {"usemmap",   no_argument,  &testops->usemmap,  1 },
      {"shuffle",   no_argument,  &testops->shuffle,  1 },
      {"help",      no_argument,  NULL,  0 },
      {0,           0,            0,     0 }
    };

    c = getopt_long(argc, argv, "p:t:f:b:d:u:a:P:", long_options, &option_index);
    if (c == -1)
      break;

    switch(c) {
      case 0:
        if (long_options[option_index].flag != 0)
          break;

        usage(pname);
        break;

      case 'P':
        if ((testops->pagesize = strtol(optarg, nullptr, 0)) > 0) {
          if (umap_cfg_set_pagesize(testops->pagesize) < 0) {
            goto R0;
          }
          break;
        }
        goto R0;
      case 'p':
        if ((testops->numpages = strtoull(optarg, nullptr, 0)) > 0)
          break;
        goto R0;
      case 't':
        if ((testops->numthreads = strtoull(optarg, nullptr, 0)) > 0)
          break;
        else goto R0;
      case 'b':
        if ((testops->bufsize = strtoull(optarg, nullptr, 0)) > 0)
          break;
        else goto R0;
      case 'u':
        if ((testops->uffdthreads = strtoull(optarg, nullptr, 0)) > 0)
          break;
        else goto R0;
      case 'a':
        if ((testops->pages_to_access = strtoull(optarg, nullptr, 0)) >= 0)
          break;
        else goto R0;
      case 'd':
        testops->dirname = optarg;
        break;
      case 'f':
        testops->filename = optarg;
        break;
      default:
      R0:
        usage(pname);
    }
  }

  if (testops->numpages < testops->pages_to_access) {
    cerr << "Invalid -a argument " << testops->pages_to_access << "\n";
    usage(pname);
  }

  if (optind < argc) {
    cerr << "Unknown Arguments: ";
    while (optind < argc)
      cerr << "\"" << argv[optind++] << "\" ";
    cerr << endl;
    usage(pname);
  }

  /*
   * Note: Care must be taken when configuring the number of threads
   * and the buffer size of umap.  When the buffer size is set, it
   * apportions the buffer evenly to the umap threads.  So setting the
   * buffer size requires that the number of threads be set properly
   * first.
   */
  if (testops->uffdthreads != umap_cfg_get_uffdthreads())
    umap_cfg_set_uffdthreads(testops->uffdthreads);

  umap_cfg_set_bufsize(testops->bufsize);
}

long umt_getpagesize(void)
{
  return umap_cfg_get_pagesize();
}
}
#endif // _COMMANDLING_HPP
Includes
  • getopt.h
  • iostream
  • stdint.h
  • umap/umap.h
  • unistd.h
Namespaces
File compute_degree_distribution.cpp

Parent directory (bfs)

Definition (bfs/compute_degree_distribution.cpp)
Program Listing for File compute_degree_distribution.cpp

Return to documentation for file (bfs/compute_degree_distribution.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <algorithm>

/// This is a utility program to compute a degree distribution
/// This program treat the input files as directed graph
/// Usage:
/// ./compute_degree_distribution [out file name] [edge list file names]
int main(int argc, char **argv) {
  if (argc < 3) {
    std::cerr << "Wrong number of arguments" << std::endl;
    std::abort();
  }

  std::string out_file_name(argv[1]);

  // -- Count degree -- //
  std::unordered_map<uint64_t, uint64_t> degree_table;
  for (int i = 2; i < argc; ++i) {
    std::ifstream input_edge_list(argv[i]);
    if (!input_edge_list.is_open()) {
      std::cerr << "Cannot open " << argv[i] << std::endl;
      continue;
    }

    uint64_t source;
    uint64_t destination;
    while (input_edge_list >> source >> destination) {
      if (degree_table.count(source) == 0) {
        degree_table[source] = 0;
      }
      ++degree_table[source];
    }
  }

  // -- Compute degree distribution table -- //
  std::unordered_map<uint64_t, uint64_t> degree_dist_table;
  for (const auto &item : degree_table) {
    const uint64_t degree = item.second;
    if (degree_dist_table.count(degree) == 0) {
      degree_dist_table[degree] = 0;
    }
    ++degree_dist_table[degree];
  }

  // -- Sort the degree distribution table -- //
  std::vector<std::pair<uint64_t, uint64_t>> sorted_degree_dist_table;
  for (const auto &item : degree_dist_table) {
    const uint64_t degree = item.first;
    const uint64_t count = item.second;
    sorted_degree_dist_table.emplace_back(degree, count);
  }
  std::sort(sorted_degree_dist_table.begin(), sorted_degree_dist_table.end(),
            [](const std::pair<uint64_t, uint64_t> &lh, const std::pair<uint64_t, uint64_t> &rh) {
              return (lh.first < rh.first); // Sort in the ascending order of degree
            });

  // -- Dump the sorted degree distribution table -- //
  std::ofstream ofs(out_file_name);
  if (!ofs.is_open()) {
    std::cerr << "Cannot open " << out_file_name << std::endl;
    std::abort();
  }
  ofs << "Degree\tCount" << std::endl;
  for (const auto &item : sorted_degree_dist_table) {
    const uint64_t degree = item.first;
    const uint64_t count = item.second;
    ofs << degree << " " << count << "\n";
  }
  ofs.close();

  std::cout << "Finished degree distribution computation" << std::endl;

  return 0;
}
Includes
File file.hpp

Parent directory (utility)

Definition (utility/file.hpp)
Program Listing for File file.hpp

Return to documentation for file (utility/file.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LIB_UTILITY_FILE_HPP
#define LIB_UTILITY_FILE_HPP

#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <unistd.h>

#include <iostream>
#include <string>

namespace utility {
void extend_file_size_manually(const int fd, const ssize_t file_size) {
  auto buffer = new unsigned char[4096];
  for (off_t i = 0; i < file_size / 4096; ++i) {
    ::pwrite(fd, buffer, 4096, i * 4096);
  }
  const size_t remained_size = file_size % 4096;
  if (remained_size > 0)
    ::pwrite(fd, buffer, remained_size, file_size - remained_size);

  ::sync();
  delete[] buffer;
}

bool extend_file_size(const int fd, const size_t file_size) {
  /// -----  extend the file if its size is smaller than that of mapped area ----- ///
#ifdef __linux__
  struct stat statbuf;
  if (::fstat(fd, &statbuf) == -1) {
    ::perror("fstat");
    std::cerr << "errno: " << errno << std::endl;
    return false;
  }
  if (::llabs(statbuf.st_size) < static_cast<ssize_t>(file_size)) {
    if (::ftruncate(fd, file_size) == -1) {
      ::perror("ftruncate");
      std::cerr << "errno: " << errno << std::endl;
      return false;
    }
  }
#else
#warning "Manually extend file size"
  extend_file_size_manually(fd, file_size);
#endif
  return true;
}

bool extend_file_size(const std::string &file_name, const size_t file_size) {
  const int fd = ::open(file_name.c_str(), O_RDWR);
  if (fd == -1) {
    ::perror("open");
    std::cerr << "errno: " << errno << std::endl;
    return false;
  }

  if (!extend_file_size(fd, file_size)) return false;
  ::close(fd);

  return true;
}

bool create_file(const std::string &file_name) {
  const int fd = ::open(file_name.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
  if (fd == -1) {
    ::perror("open");
    std::cerr << "errno: " << errno << std::endl;
    return false;
  }
  ::close(fd);

  return true;
}
}  // namespace utility

#endif //LIB_UTILITY_FILE_HPP
Includes
  • fcntl.h
  • iostream
  • string
  • sys/resource.h
  • sys/stat.h
  • sys/time.h
  • unistd.h
Namespaces
File generate_edge_list.cpp

Parent directory (bfs/rmat_edge_generator)

Definition (bfs/rmat_edge_generator/generate_edge_list.cpp)
Program Listing for File generate_edge_list.cpp

Return to documentation for file (bfs/rmat_edge_generator/generate_edge_list.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include "rmat_edge_generator.hpp"

// ---------------------------------------- //
// Option
// ---------------------------------------- //
struct rmat_option_t {
  uint64_t seed{123};
  uint64_t vertex_scale{17};
  uint64_t edge_count{(1ULL << 17) * 16};
  double a{0.57};
  double b{0.19};
  double c{0.19};
  bool scramble_id{true};
  bool generate_both_directions{true};
};

bool parse_options(int argc, char **argv, rmat_option_t *option, std::string *out_edge_list_file_name) {
  int p;
  while ((p = getopt(argc, argv, "o:s:v:e:a:b:c:r:u:")) != -1) {
    switch (p) {
      case 'o':*out_edge_list_file_name = optarg; // required
        break;

      case 's':option->seed = std::stoull(optarg);
        break;

      case 'v':option->vertex_scale = std::stoull(optarg);
        break;

      case 'e':option->edge_count = std::stoull(optarg);
        break;

      case 'a':option->a = std::stod(optarg);
        break;

      case 'b':option->b = std::stod(optarg);
        break;

      case 'c':option->c = std::stod(optarg);
        break;

      case 'r':option->scramble_id = static_cast<bool>(std::stoi(optarg));
        break;

      case 'u':option->generate_both_directions = static_cast<bool>(std::stoi(optarg));
        break;

      default:std::cerr << "Illegal option" << std::endl;
        std::abort();
    }
  }

  if (out_edge_list_file_name->empty()) {
    std::cerr << "edge list file name (-o option) is required" << std::endl;
    std::abort();
  }

  std::cout << "seed: " << option->seed
            << "\nvertex_scale: " << option->vertex_scale
            << "\nedge_count: " << option->edge_count
            << "\na: " << option->a
            << "\nb: " << option->b
            << "\nc: " << option->c
            << "\nscramble_id: " << static_cast<int>(option->scramble_id)
            << "\ngenerate_both_directions: " << static_cast<int>(option->generate_both_directions)
            << "\nout_edge_list_file_name: " << *out_edge_list_file_name << std::endl;

  return true;
}

// ---------------------------------------- //
// Main
// ---------------------------------------- //
int main(int argc, char **argv) {

  rmat_option_t rmat_option;
  std::string out_edge_list_file_name;
  parse_options(argc, argv, &rmat_option, &out_edge_list_file_name);

  rmat_edge_generator rmat(rmat_option.seed, rmat_option.vertex_scale, rmat_option.edge_count,
                           rmat_option.a, rmat_option.b, rmat_option.c,
                           1.0 - (rmat_option.a + rmat_option.b + rmat_option.c),
                           rmat_option.scramble_id, rmat_option.generate_both_directions);

  std::ofstream edge_list_file(out_edge_list_file_name);
  if (!edge_list_file.is_open()) {
    std::cerr << "Cannot open " << out_edge_list_file_name << std::endl;
    std::abort();
  }

  for (auto edge : rmat) {
    edge_list_file << edge.first << " " << edge.second << "\n";
  }
  edge_list_file.close();

  std::cout << "Finished edge list generation" << std::endl;

  return 0;
}
Includes
File hash.hpp

Parent directory (bfs/rmat_edge_generator)

Definition (bfs/rmat_edge_generator/hash.hpp)
Program Listing for File hash.hpp

Return to documentation for file (bfs/rmat_edge_generator/hash.hpp)

/*
 * This code is coming from the following project
 * /
/ *
 * Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 * Produced at the Lawrence Livermore National Laboratory.
 * Written by Roger Pearce <rpearce@llnl.gov>.
 * LLNL-CODE-644630.
 * All rights reserved.
 *
 * This file is part of HavoqGT, Version 0.1.
 * For details, see https://computation.llnl.gov/casc/dcca-pub/dcca/Downloads.html
 *
 * Please also read this link – Our Notice and GNU Lesser General Public License.
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (as published by the Free
 * Software Foundation) version 2.1 dated February 1999.
 *
 * This program 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 terms and conditions of the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * OUR NOTICE AND TERMS AND CONDITIONS OF THE GNU GENERAL PUBLIC LICENSE
 *
 * Our Preamble Notice
 *
 * A. This notice is required to be provided under our contract with the
 * U.S. Department of Energy (DOE). This work was produced at the Lawrence
 * Livermore National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE.
 *
 * B. Neither the United States Government nor Lawrence Livermore National
 * Security, LLC nor any of their employees, makes any warranty, express or
 * implied, or assumes any liability or responsibility for the accuracy,
 * completeness, or usefulness of any information, apparatus, product, or process
 * disclosed, or represents that its use would not infringe privately-owned rights.
 *
 * C. Also, reference herein to any specific commercial products, process, or
 * services by trade name, trademark, manufacturer or otherwise does not
 * necessarily constitute or imply its endorsement, recommendation, or favoring by
 * the United States Government or Lawrence Livermore National Security, LLC. The
 * views and opinions of authors expressed herein do not necessarily state or
 * reflect those of the United States Government or Lawrence Livermore National
 * Security, LLC, and shall not be used for advertising or product endorsement
 * purposes.
 *
 */

#ifndef BFS_HASH_HPP
#define BFS_HASH_HPP

#include <cstdint>

namespace rmat_edge_generator_detail {


///
/// Hash functions
///
/// \todo requires documentation!
/// \todo requires testing!

inline uint32_t hash32(uint32_t a) {
  a = (a + 0x7ed55d16) + (a << 12);
  a = (a ^ 0xc761c23c) ^ (a >> 19);
  a = (a + 0x165667b1) + (a << 5);
  a = (a + 0xd3a2646c) ^ (a << 9);
  a = (a + 0xfd7046c5) + (a << 3);
  a = (a ^ 0xb55a4f09) ^ (a >> 16);
  return a;
}

inline uint16_t hash16(uint16_t a) {
  a = (a + 0x5d16) + (a << 6);
  a = (a ^ 0xc23c) ^ (a >> 9);
  a = (a + 0x67b1) + (a << 5);
  a = (a + 0x646c) ^ (a << 7);
  a = (a + 0x46c5) + (a << 3);
  a = (a ^ 0x4f09) ^ (a >> 8);
  return a;
}

inline uint64_t shifted_n_hash32(uint64_t input, int n) {
  uint64_t to_hash = input >> n;
  uint64_t mask = 0xFFFFFFFF;
  to_hash &= mask;
  to_hash = hash32(to_hash);

  to_hash <<= n;
  mask <<= n;
  //clear bits
  input &= ~mask;
  input |= to_hash;
  return input;
}

inline uint64_t shifted_n_hash16(uint64_t input, int n) {
  uint64_t to_hash = input >> n;
  uint64_t mask = 0xFFFF;
  to_hash &= mask;
  to_hash = hash16(to_hash);

  to_hash <<= n;
  mask <<= n;
  //clear bits
  input &= ~mask;
  input |= to_hash;
  return input;
}

inline uint64_t hash_nbits(uint64_t input, int n) {
  //std::cout << "hash_nbits(" << input << ", " << n << ") = ";
  if (n == 32) {
    input = hash32(input);
  } else if (n > 32) {
    assert(n > 32);
    n -= 32;
    for (int i = 0; i <= n; ++i) {
      input = shifted_n_hash32(input, i);
    }
    for (int i = n; i >= 0; --i) {
      input = shifted_n_hash32(input, i);
    }
  } else if (n < 32) {
    assert(n < 32);
    assert(n > 16 && "Hashing less than 16bits is not supported");
    n -= 16;
    for (int i = 0; i <= n; ++i) {
      input = shifted_n_hash16(input, i);
    }
    for (int i = n; i >= 0; --i) {
      input = shifted_n_hash16(input, i);
    }
  }
  //std::cout << input << std::endl;
  return input;
}

} // namespace rmat_edge_generator_detail
#endif //BFS_HASH_HPP
Includes
  • cstdint
File ingest_edge_list.cpp

Parent directory (bfs)

Definition (bfs/ingest_edge_list.cpp)
Program Listing for File ingest_edge_list.cpp

Return to documentation for file (bfs/ingest_edge_list.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <tuple>
#include <cstring>

#include "../utility/bitmap.hpp"
#include "../utility/mmap.hpp"
#include "../utility/file.hpp"

std::pair<uint64_t, uint64_t>
check_edge_list(const std::vector<std::string> &edge_list_file_names) {
  uint64_t max_id = 0;
  size_t num_edges = 0;

  std::cout << "---------- Find max vertex ID and count #of edges ----------" << std::endl;
#ifdef _OPENMP
#pragma omp parallel for reduction(+:num_edges), reduction(max : max_id)
#endif
  for (size_t i = 0; i < edge_list_file_names.size(); ++i) {
    std::ifstream ifs(edge_list_file_names[i]);
    if (!ifs.is_open()) {
      std::cerr << "Can not open " << edge_list_file_names[i] << std::endl;
      std::abort();
    }
    std::cout << "Reading " << edge_list_file_names[i] << std::endl;

    uint64_t src, trg;
    while (ifs >> src >> trg) {
      max_id = std::max(src, max_id);
      max_id = std::max(trg, max_id);
      ++num_edges;
    }
  }

  return std::make_pair(max_id, num_edges);
}

void ingest_edges(void *const map_raw_address, const uint64_t max_id, const std::vector<std::string> &edge_list_file_names) {

  uint64_t *const index = new uint64_t[max_id + 2];
  for (size_t i = 0; i < max_id + 2; ++i) index[i] = 0;
  std::cout << static_cast<double>((max_id + 2) * sizeof(uint64_t) / (1ULL << 30))
            << " GB is allocated for index" << std::endl;

  std::cout << "---------- Count degree ----------" << std::endl;
#ifdef _OPENMP
#pragma omp parallel for
#endif
  for (size_t i = 0; i < edge_list_file_names.size(); ++i) {
    std::cout << "Reading " << edge_list_file_names[i] << std::endl;
    std::ifstream edge_stream(edge_list_file_names[i]);
    if (!edge_stream.is_open()) {
      std::cerr << "Can not open " << edge_list_file_names[i] << std::endl;
      std::abort();
    }

    uint64_t source, target;
    while (edge_stream >> source >> target) {
#ifdef _OPENMP
#pragma omp atomic
#endif
      ++index[source];
    }
  }

  std::cout << "---------- Construct index ----------" << std::endl;
  for (size_t i = max_id + 1; i > 0; --i) {
    index[i] = index[i - 1];
  }
  index[0] = 0;
  for (size_t i = 0; i < max_id + 1; ++i) {
    index[i + 1] += index[i];
  }

  std::cout << "---------- Writing index ----------" << std::endl;
  uint64_t *index_map = static_cast<uint64_t *>(map_raw_address);
  std::memcpy(index_map, index, (max_id + 2) * sizeof(uint64_t));

  std::cout << "---------- Load edges ----------" << std::endl;
  const std::ptrdiff_t edges_offset = static_cast<std::ptrdiff_t>(max_id) + 2;
  uint64_t *edges_map = static_cast<uint64_t *>(map_raw_address) + edges_offset;

#ifdef _OPENMP
#pragma omp parallel for
#endif
  for (size_t i = 0; i < edge_list_file_names.size(); ++i) {
    std::cout << "Reading " << edge_list_file_names[i] << std::endl;
    std::ifstream edge_stream(edge_list_file_names[i]);

    uint64_t source, target;
    while (edge_stream >> source >> target) {
      size_t pos;
#ifdef _OPENMP
#pragma omp atomic capture
#endif
      pos = index[source]++;
      edges_map[pos] = target;
    }
  }

  delete[] index;
}

void parse_options(int argc, char **argv,
                   std::string &graph_file_name,
                   std::vector<std::string> &edge_list_file_names) {
  graph_file_name = "";

  char c;
  while ((c = getopt(argc, argv, "g:h")) != -1) {
    switch (c) {
      case 'g': /// Required
        graph_file_name = optarg;
        break;

      case 'h':
        // usage();
        break;
    }
  }

  for (int index = optind; index < argc; index++) {
    edge_list_file_names.push_back(argv[index]);
  }
}

int main(int argc, char **argv) {
  std::string graph_file_name;
  std::vector<std::string> edge_list_file_names;

  parse_options(argc, argv, graph_file_name, edge_list_file_names);

  uint64_t max_id;
  size_t num_edges;
  std::tie(max_id, num_edges) = check_edge_list(edge_list_file_names);
  std::cout << "num_vertices: " << max_id + 1 << std::endl;
  std::cout << "num_edges: " << num_edges << std::endl;

  /// ----- create and map output (graph) file ----- ///
  const size_t graph_size = (max_id + 2 + num_edges) * sizeof(uint64_t);
  if (!utility::create_file(graph_file_name)) {
    std::cerr << "Failed to create a file: " << graph_file_name << std::endl;
    std::abort();
  }
  if (!utility::extend_file_size(graph_file_name, graph_size)) {
    std::cerr << "Failed to extend a file: " << graph_file_name << std::endl;
    std::abort();
  }

  int fd = -1;
  void *map_raw_address = nullptr;
  std::tie(fd, map_raw_address) = utility::map_file_write_mode(graph_file_name, nullptr, graph_size, 0);
  if (fd == -1 || map_raw_address == nullptr) {
    std::cerr << "Failed to map a file with write mode: " << graph_file_name << std::endl;
    std::abort();
  }

  /// ----- ingest edges ----- ///
  ingest_edges(map_raw_address, max_id, edge_list_file_names);

  /// ----- closing ----- ///
  utility::munmap(map_raw_address, graph_size, true);
  std::cout << "Edge list ingestion is finished" << std::endl;

  return 0;
}
Includes
  • ../utility/bitmap.hpp
  • ../utility/file.hpp
  • ../utility/mmap.hpp
  • algorithm
  • cstring
  • fcntl.h
  • fstream
  • iostream
  • string
  • sys/mman.h
  • tuple
  • unistd.h
  • vector (File run_random_vector.cpp)
File INSTRUCTION.md

Parent directory (median_calculation)

Definition (median_calculation/INSTRUCTION.md)
Program Listing for File INSTRUCTION.md

Return to documentation for file (median_calculation/INSTRUCTION.md)

# Build
Under construction...

# Run
```sh
$ ls /mnt/ssd/
asteroid_sim_epoch10.fits  asteroid_sim_epoch2.fits  asteroid_sim_epoch4.fits  asteroid_sim_epoch6.fits  asteroid_sim_epoch8.fits
asteroid_sim_epoch1.fits   asteroid_sim_epoch3.fits  asteroid_sim_epoch5.fits  asteroid_sim_epoch7.fits  asteroid_sim_epoch9.fits

$ cd /path/to/umap/build/directory/
$ env NUM_VECTORS=10000 ./tests/median_calculation/run_random_vector -f /mnt/ssd/asteroid_sim_epoch
```
File mmap.hpp

Parent directory (utility)

Definition (utility/mmap.hpp)
Program Listing for File mmap.hpp

Return to documentation for file (utility/mmap.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SIMPLE_BFS_MMAP_UTILITY_HPP
#define SIMPLE_BFS_MMAP_UTILITY_HPP

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <cstddef>

#include "file.hpp"

namespace utility {

/// \brief Get the page size
/// \return The size of page size. Return -1 for error cases.
ssize_t get_page_size() {
  const ssize_t page_size = ::sysconf(_SC_PAGE_SIZE);
  if (page_size == -1) {
    ::perror("sysconf(_SC_PAGE_SIZE)");
    std::cerr << "errno: " << errno << std::endl;
  }

  return page_size;
}

/// \brief Maps a file checking errors
/// \param addr Same as mmap(2)
/// \param length Same as mmap(2)
/// \param protection Same as mmap(2)
/// \param flags Same as mmap(2)
/// \param fd Same as mmap(2)
/// \param offset  Same as mmap(2)
/// \return On success, returns a pointer to the mapped area.
/// On error, nullptr is returned.
void *map_file(void *const addr, const size_t length, const int protection, const int flags,
               const int fd, const off_t offset) {
  const ssize_t page_size = get_page_size();
  if (page_size == -1) {
    return nullptr;
  }

  if ((std::ptrdiff_t)addr % page_size != 0) {
    std::cerr << "address (" << addr << ") is not page aligned ("
              << ::sysconf(_SC_PAGE_SIZE) << ")" << std::endl;
    return nullptr;
  }

  if (offset % page_size != 0) {
    std::cerr << "offset (" << offset << ") is not a multiple of the page size (" << ::sysconf(_SC_PAGE_SIZE) << ")"
              << std::endl;
    return nullptr;
  }

  /// ----- Map the file ----- ///
  void *mapped_addr = ::mmap(addr, length, protection, flags, fd, offset);
  if (mapped_addr == MAP_FAILED) {
    ::perror("mmap");
    std::cerr << "errno: " << errno << std::endl;
    return nullptr;
  }

  if ((std::ptrdiff_t)mapped_addr % page_size != 0) {
    std::cerr << "mapped address (" << mapped_addr << ") is not page aligned ("
              << ::sysconf(_SC_PAGE_SIZE) << ")" << std::endl;
    return nullptr;
  }

  return mapped_addr;
}

/// \brief Maps a file with read mode
/// \param file_name The name of file to be mapped
/// \param addr Normally nullptr; if this is not nullptr the kernel takes it as a hint about where to place the mapping
/// \param length The length of the map
/// \param offset The offset in the file
/// \return On Success, returns a pair of the file descriptor of the file and the starting address for the map.
/// On error, retuns a pair of -1 and nullptr.
std::pair<int, void *> map_file_read_mode(const std::string &file_name, void *const addr,
                                          const size_t length, const off_t offset,
                                          const int additional_flags = 0) {
  /// ----- Open the file ----- ///
  const int fd = ::open(file_name.c_str(), O_RDONLY);
  if (fd == -1) {
    ::perror("open");
    std::cerr << "errno: " << errno << std::endl;
    return std::make_pair(-1, nullptr);
  }

  /// ----- Map the file ----- ///
  void *mapped_addr = map_file(addr, length, PROT_READ, MAP_SHARED | additional_flags, fd, offset);
  if (mapped_addr == nullptr) {
    close(fd);
    return std::make_pair(-1, nullptr);
  }

  return std::make_pair(fd, mapped_addr);
}

/// \brief Maps a file with write mode
/// \param file_name The name of a file to be mapped
/// \param addr Normally nullptr; if this is not nullptr the kernel takes it as a hint about where to place the mapping
/// \param length The length of the map
/// \param offset The offset in the file
/// \return On Success, returns a pair of the file descriptor of the file and the starting address for the map.
/// On error, retuns a pair of -1 and nullptr.
std::pair<int, void *> map_file_write_mode(const std::string &file_name, void *const addr,
                                           const size_t length, const off_t offset,
                                           const int additional_flags = 0) {
  /// ----- Open the file ----- ///
  const int fd = ::open(file_name.c_str(), O_RDWR);
  if (fd == -1) {
    ::perror("open");
    std::cerr << "errno: " << errno << std::endl;
    return std::make_pair(-1, nullptr);
  }

  /// ----- Map the file ----- ///
  void *mapped_addr = map_file(addr, length, PROT_READ | PROT_WRITE, MAP_SHARED | additional_flags, fd, offset);
  if (mapped_addr == nullptr) {
    close(fd);
    return std::make_pair(-1, nullptr);
  }

  return std::make_pair(fd, mapped_addr);
}

void msync(void *const addr, const size_t length) {
  if (::msync(addr, length, MS_SYNC) != 0) {
    ::perror("msync");
    std::cerr << "errno: " << errno << std::endl;
  }
}

void munmap(void *const addr, const size_t length, const bool call_msync) {
  if (call_msync) msync(addr, length);

  if (::munmap(addr, length) != 0) {
    ::perror("munmap");
    std::cerr << "errno: " << errno << std::endl;
  }
}

} // namespace utility

#endif //SIMPLE_BFS_MMAP_UTILITY_HPP
Includes
  • cstddef
  • fcntl.h
  • file.hpp (File file.hpp)
  • iostream
  • stdio.h
  • stdlib.h
  • sys/mman.h
  • sys/stat.h
  • sys/types.h
  • unistd.h
Namespaces
File nvmebenchmark.cpp

Parent directory (pfbenchmark)

Definition (pfbenchmark/nvmebenchmark.cpp)
Program Listing for File nvmebenchmark.cpp

Return to documentation for file (pfbenchmark/nvmebenchmark.cpp)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT
 * file in the top level directory, or at https://github.com/LLNL/umap/blob/master/COPYRIGHT
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (as published by the Free
 * Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA 02111-1307 USA
 *
 * This program is a benchmark for NVME device I/O bandwidth which provides the average
 * time in nanoseconds for performing the following I/O operations:
 *
 * 1) Page (4K) writes to a file on the NVME device
 * 2) Page (4K) reads from a file on the NVME device
 *
 * A number of threads may be specified on the command line to enable concurrent I/O
 * access within the file.  Further, the file may be accessed sequentially (default)
 * or randomly (if "--shuffle" command line option is specified).
 */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>
#include <chrono>
#include <omp.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <string>
#include <sstream>
#include <vector>
#include <random>
#include <algorithm>
#include <iterator>

#include "umap/umap.h"
#include "../utility/commandline.hpp"

using namespace std;
using namespace chrono;
static uint64_t pagesize;
static uint64_t pages_to_access;
static char** tmppagebuf; // One per thread
static int fd;
static utility::umt_optstruct_t options;
vector<uint64_t> shuffled_indexes;

void do_write_pages(uint64_t pages)
{
#pragma omp parallel for
  for (uint64_t i = 0; i < pages; ++i) {
    uint64_t myidx = shuffled_indexes[i];
    uint64_t* ptr = (uint64_t*)tmppagebuf[omp_get_thread_num()];
    *ptr = myidx * pagesize/sizeof(uint64_t);
    if (pwrite(fd, ptr, pagesize, myidx*pagesize) < 0) {
      perror("pwrite");
      exit(1);
    }
  }
}

void do_read_pages(uint64_t pages)
{
#pragma omp parallel for
  for (uint64_t i = 0; i < pages; ++i) {
    uint64_t myidx = shuffled_indexes[i];
    uint64_t* ptr = (uint64_t*)tmppagebuf[omp_get_thread_num()];
    if (pread(fd, ptr, pagesize, myidx*pagesize) < 0) {
      perror("pread");
      exit(1);
    }
    if ( *ptr != myidx * pagesize/sizeof(uint64_t) ) {
      cout << i << " " << myidx << " " << *ptr << " != " << (myidx * pagesize/sizeof(uint64_t)) << "\n";
      exit(1);
    }
  }
}

int read_pages(int argc, char **argv)
{
  fd = open(options.filename, O_RDWR | O_LARGEFILE | O_DIRECT);

  if (fd == -1) {
    perror("open failed\n");
    exit(1);
  }

  auto start_time = chrono::high_resolution_clock::now();
  do_read_pages(pages_to_access);
  auto end_time = chrono::high_resolution_clock::now();

  cout << "nvme,"
      << "+IO,"
      << (( options.shuffle == 1) ? "shuffle" : "seq") << ","
      << "read,"
      << options.numthreads << ","
      << 0 << ","
      << chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count() / pages_to_access << "\n";

  close(fd);
  return 0;
}

int write_pages(int argc, char **argv)
{
  if ( !options.noinit ) {
    cout << "Removing " << options.filename << "\n";
    unlink(options.filename);
    cout << "Creating " << options.filename << "\n";
    fd = open(options.filename, O_RDWR | O_LARGEFILE | O_DIRECT | O_CREAT, S_IRUSR | S_IWUSR);
  }
  else {
    fd = open(options.filename, O_RDWR | O_LARGEFILE | O_DIRECT);
  }

  if (fd == -1) {
    perror("open failed\n");
    exit(1);
  }

  auto start_time = chrono::high_resolution_clock::now();
  do_write_pages(pages_to_access);
  auto end_time = chrono::high_resolution_clock::now();

  cout << "nvme,"
      << "+IO,"
      << (( options.shuffle == 1) ? "shuffle" : "seq") << ","
      << "write,"
      << options.numthreads << ","
      << 0 << ","
      << chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count() / pages_to_access << "\n";

  close(fd);
  return 0;
}

int main(int argc, char **argv)
{
  int rval = 0;
  std::random_device rd;
  std::mt19937 g(rd());

  umt_getoptions(&options, argc, argv);

  for (uint64_t i = 0; i < options.numpages; ++i)
    shuffled_indexes.push_back(i);

  pages_to_access = options.pages_to_access ? options.pages_to_access : options.numpages;

  if ( options.shuffle )
    std::shuffle(shuffled_indexes.begin(), shuffled_indexes.end(), g);

  omp_set_num_threads(options.numthreads);
  pagesize = (uint64_t)utility::umt_getpagesize();

  tmppagebuf = (char**)calloc(options.numthreads, sizeof(char*));

  for (int i = 0; i < options.numthreads; ++i) {
    if (posix_memalign((void**)&tmppagebuf[i], (uint64_t)512, pagesize)) {
      cerr << "ERROR: posix_memalign: failed\n";
      exit(1);
    }

    if (tmppagebuf[i] == nullptr) {
      cerr << "Unable to allocate " << pagesize << " bytes for temporary buffer\n";
      exit(1);
    }
  }

  if (strcmp(argv[0], "nvmebenchmark-write") == 0)
    rval = write_pages(argc, argv);
  else if (strcmp(argv[0], "nvmebenchmark-read") == 0)
    rval = read_pages(argc, argv);

  return rval;
}
Includes
File options.cpp

Parent directory (churn)

Definition (churn/options.cpp)
Program Listing for File options.cpp

Return to documentation for file (churn/options.cpp)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT file in the top level directory, or at https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (as published by the Free Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>     // cout/cerr
#include <unistd.h>     // getopt()
#include <getopt.h>     // duh...
#include "options.h"
#include "umap/umap.h"

static char const* FILENAME = "/tmp/abc";
static const uint64_t NUMCHURNPAGES = 99;
static const uint64_t NUMLOADPAGES = 1;
static const uint64_t NUMCHURNTHREADS = 48;
static const uint64_t NUMLOADREADERS = 48;
static const uint64_t NUMLOADWRITERS = 48;
static const uint64_t TESTDURATION = 60;

using namespace std;

static void usage(char* pname)
{
  cerr
  << "Usage: " << pname << " [Options...]\n\n"
  << " --help                       - This message\n"
  << " --initonly                   - Initialize only\n"
  << " --noinit                     - No Initialization\n"
  << " --directio                   - Use O_DIRECT for file IO\n"
  << " --usemmap                    - Use mmap instead of umap\n"
  << " -b # of pages in page buffer - default: " << umap_cfg_get_bufsize() << " Pages\n"
  << " -c # of churn pages          - default: " << NUMCHURNPAGES << " Pages\n"
  << " -l # of load pages           - default: " << NUMLOADPAGES << " Pages\n"
  << " -t # of churn threads        - default: " << NUMCHURNTHREADS << endl
  << " -r # of load reader threads  - default: " << NUMLOADREADERS << endl
  << " -w # of load writer threads  - default: " << NUMLOADWRITERS << endl
  << " -f [backing file name]       - default: " << FILENAME << endl
  << " -d # seconds to run test     - default: " << TESTDURATION << " seconds\n";
  exit(1);
}

void getoptions(options_t& testops, int& argc, char **argv)
{
  int c;
  char *pname = argv[0];

  testops.iodirect=0;
  testops.usemmap=0;
  testops.noinit=0;
  testops.initonly=0;
  testops.num_churn_pages=NUMCHURNPAGES;
  testops.num_churn_threads=NUMCHURNTHREADS;
  testops.num_load_pages=NUMLOADPAGES;
  testops.num_load_reader_threads=NUMLOADREADERS;
  testops.num_load_writer_threads=NUMLOADWRITERS;
  testops.fn=FILENAME;
  testops.testduration=TESTDURATION;
  testops.page_buffer_size = umap_cfg_get_bufsize();

  while (1) {
    int option_index = 0;
    static struct option long_options[] = {
      {"directio",  no_argument,  &testops.iodirect, 1 },
      {"usemmap",   no_argument,  &testops.usemmap,  1 },
      {"initonly",  no_argument,  &testops.initonly, 1 },
      {"noinit",    no_argument,  &testops.noinit,   1 },
      {"help",      no_argument,  NULL,  0 },
      {0,           0,            0,     0 }
    };

    c = getopt_long(argc, argv, "b:c:l:t:r:w:f:d:", long_options, &option_index);
    if (c == -1)
      break;

    switch(c) {
      case 0:
        if (long_options[option_index].flag != 0)
          break;

        usage(pname);
        break;

      case 'b':
        if ((testops.page_buffer_size = strtoull(optarg, nullptr, 0)) > 0)
          break;
        goto R0;
      case 'c':
        if ((testops.num_churn_pages = strtoull(optarg, nullptr, 0)) > 0)
          break;
        goto R0;
      case 'l':
        if ((testops.num_load_pages = strtoull(optarg, nullptr, 0)) > 0)
          break;
        goto R0;

      case 'd':
        if ((testops.testduration = strtoull(optarg, nullptr, 0)) > 0)
          break;
        goto R0;
      case 'f':
        testops.fn = optarg;
        break;
      case 'w':
        if ((testops.num_load_writer_threads = strtoull(optarg, nullptr, 0)) >= 0)
          break;
        goto R0;
      case 'r':
        if ((testops.num_load_reader_threads = strtoull(optarg, nullptr, 0)) >= 0)
          break;
        goto R0;
      case 't':
        if ((testops.num_churn_threads = strtoull(optarg, nullptr, 0)) >= 0)
          break;
        goto R0;

      default:
      R0:
        usage(pname);
    }
  }

  if (optind < argc) {
    cerr << "Unknown Arguments: ";
    while (optind < argc)
      cerr << "\"" << argv[optind++] << "\" ";
    cerr << endl;
    usage(pname);
  }

  umap_cfg_set_bufsize(testops.page_buffer_size);
}
Includes
File options.h

Parent directory (churn)

Definition (churn/options.h)
Program Listing for File options.h

Return to documentation for file (churn/options.h)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT file in the top level directory, or at https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (as published by the Free Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _OPTIONS_H
#define _OPTIONS_H
#include <stdint.h>
#include "options.h"

typedef struct {
  int iodirect;
  int usemmap;
  int initonly;
  int noinit;

  uint64_t page_buffer_size;    // # of pages that page buffer can hold

  uint64_t num_churn_pages;
  uint64_t num_load_pages;

  uint64_t num_churn_threads;

  uint64_t num_load_reader_threads;
  uint64_t num_load_writer_threads;

  char const* fn;               // Backing file name

  uint64_t testduration;        // Duration (in seconds) to run test
} options_t;

void getoptions(options_t&, int&, char **argv);
#endif // _OPTIONS_H
Includes
File pfbenchmark.cpp

Parent directory (pfbenchmark)

Definition (pfbenchmark/pfbenchmark.cpp)
Program Listing for File pfbenchmark.cpp

Return to documentation for file (pfbenchmark/pfbenchmark.cpp)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT
 * file in the top level directory, or at https://github.com/LLNL/umap/blob/master/COPYRIGHT
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (as published by the Free
 * Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA 02111-1307 USA
 *
 * This program is a benchmark for UMAP page fault handling.  The specied backing file
 * for UMAP is accessed a page at a time indirectly by accessing pages that have been
 * mapped to the file.  Read accesses to memory will determine the average nanosecond
 * cost for servicing a READ PAGE FAULT and write accesses to memory will determine
 * the average cost of WRITE PAGE FAULTs.
 *
 * A number of threads may be specified on the command line to enable concurrent I/O
 * access within the file.  Further, the file may be accessed sequentially (default)
 * or randomly (if "--shuffle" command line option is specified).
 */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>
#include <chrono>
#include <omp.h>
#include <string.h>
#include <vector>
#include <random>
#include <algorithm>
#include <iterator>

#include "umap/umap.h"
#include "../utility/umap_file.hpp"
#include "../utility/commandline.hpp"

using namespace std;
using namespace chrono;
static bool usemmap = false;
static uint64_t pagesize;
static uint64_t page_step;
static uint64_t* glb_array;
static utility::umt_optstruct_t options;
static uint64_t pages_to_access;
vector<uint64_t> shuffled_indexes;

void do_write_pages(uint64_t page_step, uint64_t pages)
{
#pragma omp parallel for
  for (uint64_t i = 0; i < pages; ++i) {
    uint64_t myidx = shuffled_indexes[i];
    glb_array[myidx * page_step] = (myidx * page_step);
  }
}

uint64_t do_read_pages(uint64_t page_step, uint64_t pages)
{
  uint64_t x;

  // Weird logic to make sure that compiler doesn't optimize out our read of glb_array[i]
#pragma omp parallel for
  for (uint64_t i = 0; i < pages; ++i) {
    uint64_t myidx = shuffled_indexes[i];
    x = glb_array[myidx * page_step];

    if (x != (myidx * page_step)) {
      cout << __FUNCTION__ << "glb_array[" << myidx * page_step << "]: (" << glb_array[myidx*page_step] << ") != " << myidx * page_step << "\n";
      exit(1);
    }
  }

  return x;
}

uint64_t do_read_modify_write_pages(uint64_t page_step, uint64_t pages)
{
  uint64_t x;

  // Weird logic to make sure that compiler doesn't optimize out our read of glb_array[i]
#pragma omp parallel for
  for (uint64_t i = 0; i < pages; ++i) {
    uint64_t myidx = shuffled_indexes[i];
    x = glb_array[myidx * page_step];

    if (x != (myidx * page_step)) {
      cout << __FUNCTION__ << "glb_array[" << myidx * page_step << "]: (" << x << ") != " << myidx * page_step << "\n";
      exit(1);
    }
    else {
      glb_array[myidx * page_step] = (myidx * page_step);
      x++;
    }
  }
  return x;
}

void print_stats( void )
{
  if (!usemmap) {
    struct umap_cfg_stats s;
    umap_cfg_get_stats(glb_array, &s);

    //cout << s.dirty_evicts << " Dirty Evictions\n";
    //cout << s.clean_evicts << " Clean Evictions\n";
    //cout << s.evict_victims << " Victims\n";
    //cout << s.wp_messages << " WP Faults\n";
    //cout << s.read_faults << " Read Faults\n";
    //cout << s.write_faults << " Write Faults\n";
    if (s.sigbus)
      cout << s.sigbus << " SIGBUS Signals\n";
    if (s.stuck_wp)
      cout << s.stuck_wp << " Stuck WP Workarounds\n";
    //cout << s.dropped_dups << " Dropped Duplicates\n";
  }
}

int read_test(int argc, char **argv)
{
  auto start_time = chrono::high_resolution_clock::now();
  do_read_pages(page_step, pages_to_access);
  auto end_time = chrono::high_resolution_clock::now();

  cout << ((options.usemmap == 1) ? "mmap" : "umap") << ","
      << (( options.shuffle == 1) ? "shuffle" : "seq") << ","
      << "read,"
      << options.numthreads << ","
      << options.uffdthreads << ","
      << chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count() / pages_to_access << "\n";

  return 0;
}

int write_test(int argc, char **argv)
{
  auto start_time = chrono::high_resolution_clock::now();
  do_write_pages(page_step, pages_to_access);
  auto end_time = chrono::high_resolution_clock::now();

  cout << ((options.usemmap == 1) ? "mmap" : "umap") << ","
      << (( options.shuffle == 1) ? "shuffle" : "seq") << ","
      << "write,"
      << options.numthreads << ","
      << options.uffdthreads << ","
      << chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count() / pages_to_access << "\n";

  return 0;
}

int read_modify_write_test(int argc, char **argv)
{
  auto start_time = chrono::high_resolution_clock::now();
  auto end_time = chrono::high_resolution_clock::now();

  start_time = chrono::high_resolution_clock::now();
  do_read_modify_write_pages(page_step, pages_to_access);
  end_time = chrono::high_resolution_clock::now();

  cout << ((options.usemmap == 1) ? "mmap" : "umap") << ","
      << (( options.shuffle == 1) ? "shuffle" : "seq") << ","
      << "rmw,"
      << options.numthreads << ","
      << options.uffdthreads << ","
      << chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count() / pages_to_access << "\n";

  return 0;
}

int main(int argc, char **argv)
{
  int rval = -1;
  std::random_device rd;
  std::mt19937 g(rd());

  umt_getoptions(&options, argc, argv);

  for (uint64_t i = 0; i < options.numpages; ++i)
    shuffled_indexes.push_back(i);

  pages_to_access = options.pages_to_access ? options.pages_to_access : options.numpages;

  if ( options.shuffle )
    std::shuffle(shuffled_indexes.begin(), shuffled_indexes.end(), g);

  options.initonly = 0;
  usemmap = (options.usemmap == 1);
  omp_set_num_threads(options.numthreads);
  pagesize = (uint64_t)utility::umt_getpagesize();
  page_step = pagesize/sizeof(uint64_t);

  glb_array = (uint64_t*) utility::map_in_file(options.filename, options.initonly,
      options.noinit, options.usemmap, pagesize * options.numpages);

  if (strcmp(argv[0], "pfbenchmark-read") == 0)
    rval = read_test(argc, argv);
  else if (strcmp(argv[0], "pfbenchmark-write") == 0)
    rval = write_test(argc, argv);
  else if (strcmp(argv[0], "pfbenchmark-readmodifywrite") == 0)
    rval = read_modify_write_test(argc, argv);
  else
    cerr << "Unknown test mode " << argv[0] << "\n";

  print_stats();
  utility::unmap_file(options.usemmap, pagesize * options.numpages, glb_array);
  return rval;
}
Includes
File README.md

Parent directory (bfs)

Definition (bfs/README.md)
Program Listing for File README.md

Return to documentation for file (bfs/README.md)

## Generate edge list using a R-MAT generator
```
./rmat_edge_generator/generate_edge_list

-o [out edge list file name (required)]

-s [seed for random number generator; default is 123]

-v [SCALE; The logarithm base two of the number of vertices; default is 17]

-e [#of edges; default is 2^{SCALE} x 16]

-a [initiator parameter A; default is 0.57]

-b [initiator parameter B; default is 0.19]

-c [initiator parameter C; default is 0.19]

-r [if true, scrambles edge IDs; default is true]

-u [if true, generates edges for the both direction; default is true]
```

* As for the initiator parameters,
see [Graph500, 3.2 Detailed Text Description](https://graph500.org/?page_id=12#sec-3_2) for more details.

#### Generate Graph 500 inputs
```
./generate_edge_list -o /mnt/ssd/edge_list -v 20 -e $((2**20*16))
````
This command generates a edge list file (/mnt/ssd/edge_list) which contains the edges of a SCALE 20 graph.
In Graph 500, the number of edges of a graph is #vertives x 16 (16 is called 'edge factor').

## Ingest Edge List (construct CSR graph)
```
./ingest_edge_list -g /l/ssd/csr_graph_file /l/ssd/edgelist1 /l/ssd/edgelist2
```

* Load edge data from files /l/ssd/edgelist1 and /l/ssd/edgelist2 (you can specify an arbitrary number of files).
A CSR graph is constructed in /l/ssd/csr_graph_file.
* Each line of input files must be a pair of source and destination vertex IDs (unsigned 64bit number).
* This program treats inputs as a directed graph, that is, it does not ingest edges for both directions.
* This is a multi-threads (OpenMP) program.
You can control the number of threads using the environment variable OMP_NUM_THREADS.
* As for real-world datasets, [SNAP Datasets](http://snap.stanford.edu/data/index.html) is popular in the graph processing community.
Please note that some datasets in SNAP are a little different.
For example, the first line is a comment; you have to delete the line before running this program.

## Run BFS
```
./run_bfs -n \[#of vertices\] -m \[#of edges\] -g \[/path/to/graph_file\]
```

* You can get #of vertices and #of edges by running ingest_edge_list.
* This is a multi-threads (OpenMP) program.
You can control the number of threads using the environment variable OMP_NUM_THREADS.
File rmat_edge_generator.hpp

Parent directory (bfs/rmat_edge_generator)

Definition (bfs/rmat_edge_generator/rmat_edge_generator.hpp)
Program Listing for File rmat_edge_generator.hpp

Return to documentation for file (bfs/rmat_edge_generator/rmat_edge_generator.hpp)

/*
 * Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 * Produced at the Lawrence Livermore National Laboratory.
 * Written by Roger Pearce <rpearce@llnl.gov>.
 * LLNL-CODE-644630.
 * All rights reserved.
 *
 * This file is part of HavoqGT, Version 0.1.
 * For details, see https://computation.llnl.gov/casc/dcca-pub/dcca/Downloads.html
 *
 * Please also read this link – Our Notice and GNU Lesser General Public License.
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (as published by the Free
 * Software Foundation) version 2.1 dated February 1999.
 *
 * This program 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 terms and conditions of the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * OUR NOTICE AND TERMS AND CONDITIONS OF THE GNU GENERAL PUBLIC LICENSE
 *
 * Our Preamble Notice
 *
 * A. This notice is required to be provided under our contract with the
 * U.S. Department of Energy (DOE). This work was produced at the Lawrence
 * Livermore National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE.
 *
 * B. Neither the United States Government nor Lawrence Livermore National
 * Security, LLC nor any of their employees, makes any warranty, express or
 * implied, or assumes any liability or responsibility for the accuracy,
 * completeness, or usefulness of any information, apparatus, product, or process
 * disclosed, or represents that its use would not infringe privately-owned rights.
 *
 * C. Also, reference herein to any specific commercial products, process, or
 * services by trade name, trademark, manufacturer or otherwise does not
 * necessarily constitute or imply its endorsement, recommendation, or favoring by
 * the United States Government or Lawrence Livermore National Security, LLC. The
 * views and opinions of authors expressed herein do not necessarily state or
 * reflect those of the United States Government or Lawrence Livermore National
 * Security, LLC, and shall not be used for advertising or product endorsement
 * purposes.
 *
 */

#ifndef BFS_RMAT_EDGE_GENERATOR_HPP
#define BFS_RMAT_EDGE_GENERATOR_HPP

#include <iostream>
#include <random>
#include <cassert>
#include "hash.hpp"

#include <utility>

/// RMAT edge generator, based on Boost Graph's RMAT generator
///
/// Options include scrambling vertices based on a hash funciton, and
/// symmetrizing the list.   Generated edges are not sorted.  May contain
/// duplicate and self edges.
class rmat_edge_generator {

 public:
  typedef uint64_t vertex_descriptor;
  typedef std::pair<uint64_t, uint64_t> value_type;
  typedef value_type edge_type;

  ///
  /// InputIterator class for rmat_edge_generator

  class input_iterator_type : public std::iterator<std::input_iterator_tag,
                                                   edge_type,
                                                   ptrdiff_t,
                                                   const edge_type *,
                                                   const edge_type &> {

   public:
    input_iterator_type(rmat_edge_generator *ptr_rmat, uint64_t count)
        : m_ptr_rmat(ptr_rmat), m_rng(ptr_rmat->m_seed), m_dis(0.0, 1.0), m_count(count), m_make_undirected(false) {
      if (m_count == 0) {
        get_next();
        m_count = 0; //reset to zero
      }
    }

    const edge_type &operator*() const { return m_current; }
    //const uint64_t* operator->() const { return &(operator*()); }
    input_iterator_type &operator++() {
      get_next();
      return *this;
    }

    input_iterator_type operator++(int) {
      input_iterator_type __tmp = *this;
      get_next();
      return __tmp;
    }

    edge_type *operator->() {
      return &m_current;
    }

    bool is_equal(const input_iterator_type &_x) const {
      return m_count == (_x.m_count);
    }

    ///  Return true if x and y are both end or not end, or x and y are the same.
    friend bool
    operator==(const input_iterator_type &x, const input_iterator_type &y) { return x.is_equal(y); }

    ///  Return false if x and y are both end or not end, or x and y are the same.
    friend bool
    operator!=(const input_iterator_type &x, const input_iterator_type &y) { return !x.is_equal(y); }

   private:
    input_iterator_type();

    void get_next() {
      if (m_ptr_rmat->m_undirected && m_make_undirected) {
        std::swap(m_current.first, m_current.second);
        m_make_undirected = false;
      } else {
        m_current = m_ptr_rmat->generate_edge(m_rng, m_dis);
        ++m_count;
        m_make_undirected = true;
      }
      assert(m_current.first <= m_ptr_rmat->max_vertex_id());
      assert(m_current.second <= m_ptr_rmat->max_vertex_id());
    }

    rmat_edge_generator *m_ptr_rmat;
    std::mt19937 m_rng;
    std::uniform_real_distribution<> m_dis;
    uint64_t m_count;
    edge_type m_current;
    bool m_make_undirected;
  };

  /// seed used to be 5489
  rmat_edge_generator(uint64_t seed, uint64_t vertex_scale,
                      uint64_t edge_count, double a, double b, double c,
                      double d, bool scramble, bool undirected)
      : m_seed(seed),
        m_rng(seed),
        m_dis(0.0, 1.0),
        m_vertex_scale(vertex_scale),
        m_edge_count(edge_count),
        m_scramble(scramble),
        m_undirected(undirected),
        m_rmat_a(a),
        m_rmat_b(b),
        m_rmat_c(c),
        m_rmat_d(d) {

    //  sanity_max_vertex_id();

    // #ifdef DEBUG
    //   auto itr1 = begin();
    //   auto itr2 = begin();
    //   while (itr1 != end()) {
    //     assert(itr2 != end());
    //     assert(*itr1 == *itr2);
    //     assert(itr1 == itr2);
    //     itr1++;
    //     itr2++;
    //   }
    // #endif
  }

  /// Returns the begin of the input iterator
  input_iterator_type begin() {
    return input_iterator_type(this, 0);
  }

  /// Returns the end of the input iterator
  input_iterator_type end() {
    return input_iterator_type(this, m_edge_count);
  }

  void sanity_max_vertex_id() {
    auto itr = begin();
    auto itr_end = end();

    uint64_t value = 0;
    while (itr != itr_end) {
      value = std::max(value, (*itr).first);
      value = std::max(value, (*itr).second);
    }

    std::cout << " value: " << value << std::endl;
    assert(max_vertex_id() == value);

  }
  uint64_t max_vertex_id() {
    return (uint64_t(1) << uint64_t(m_vertex_scale)) - 1;
  }

  size_t size() {
    return m_edge_count;
  }

 protected:
  /// Generates a new RMAT edge.  This function was adapted from the Boost Graph Library.
  edge_type generate_edge() {
    return generate_edge(m_rng, m_dis);
  }
  edge_type generate_edge(std::mt19937& rng, std::uniform_real_distribution<> &dis) {
    double rmat_a = m_rmat_a;
    double rmat_b = m_rmat_b;
    double rmat_c = m_rmat_c;
    double rmat_d = m_rmat_d;
    uint64_t u = 0, v = 0;
    uint64_t step = (uint64_t(1) << m_vertex_scale) / 2;
    for (unsigned int j = 0; j < m_vertex_scale; ++j) {
      double p = dis(rng);

      if (p < rmat_a);
      else if (p >= rmat_a && p < rmat_a + rmat_b)
        v += step;
      else if (p >= rmat_a + rmat_b && p < rmat_a + rmat_b + rmat_c)
        u += step;
      else { // p > a + b + c && p < a + b + c + d
        u += step;
        v += step;
      }

      step /= 2;

      // 0.2 and 0.9 are hardcoded in the reference SSCA implementation.
      // The maximum change in any given value should be less than 10%
      rmat_a *= 0.9 + 0.2 * dis(rng);
      rmat_b *= 0.9 + 0.2 * dis(rng);
      rmat_c *= 0.9 + 0.2 * dis(rng);
      rmat_d *= 0.9 + 0.2 * dis(rng);

      double S = rmat_a + rmat_b + rmat_c + rmat_d;

      rmat_a /= S;
      rmat_b /= S;
      rmat_c /= S;
      // d /= S;
      // Ensure all values add up to 1, regardless of floating point errors
      rmat_d = 1. - rmat_a - rmat_b - rmat_c;
    }
    if (m_scramble) {
      u = rmat_edge_generator_detail::hash_nbits(u, m_vertex_scale);
      v = rmat_edge_generator_detail::hash_nbits(v, m_vertex_scale);
    }

    return std::make_pair(u, v);
  }

  const uint64_t m_seed;
  std::mt19937 m_rng;
  std::uniform_real_distribution<> m_dis;
  const uint64_t m_vertex_scale;
  const uint64_t m_edge_count;
  const bool m_scramble;
  const bool m_undirected;
  const double m_rmat_a;
  const double m_rmat_b;
  const double m_rmat_c;
  const double m_rmat_d;
};

#endif //BFS_RMAT_EDGE_GENERATOR_HPP
Includes
File run_bfs.cpp

Parent directory (bfs)

Definition (bfs/run_bfs.cpp)
Program Listing for File run_bfs.cpp

Return to documentation for file (bfs/run_bfs.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
#include <fstream>

#include "bfs_kernel.hpp"
#include "../utility/bitmap.hpp"
#include "../utility/mmap.hpp"

void parse_options(int argc, char **argv,
                   size_t &num_vertices, size_t &num_edges,
                   std::string &graph_file_name) {
  num_vertices = 0;
  num_edges = 0;
  graph_file_name = "";

  char c;
  while ((c = getopt(argc, argv, "n:m:g:h")) != -1) {
    switch (c) {
      case 'n': /// Required
        num_vertices = std::stoull(optarg);
        break;

      case 'm': /// Required
        num_edges = std::stoull(optarg);
        break;

      case 'g': /// Required
        graph_file_name = optarg;
        break;

      case 'h':
        // usage();
        break;
    }
  }
}

std::pair<uint64_t *, uint64_t *>
map_graph(const size_t num_vertices, const size_t num_edges, const std::string &graph_file_name) {
  const size_t graph_size = (num_vertices + 1 + num_edges) * sizeof(uint64_t);

  int fd = -1;
  void *map_raw_address = nullptr;
  std::tie(fd, map_raw_address) = utility::map_file_read_mode(graph_file_name, nullptr, graph_size, 0);
  if (fd == -1 || map_raw_address == nullptr) {
    std::cerr << "Failed to map the graph" << std::endl;
    std::abort();
  }

  uint64_t *index = static_cast<uint64_t *>(map_raw_address);
  const std::ptrdiff_t edges_offset = num_vertices + 1;
  uint64_t *edges = static_cast<uint64_t *>(map_raw_address) + edges_offset;

  return std::make_pair(index, edges);
}

void find_bfs_root(const size_t num_vertices, const uint64_t *const index, uint16_t *const level) {
  for (uint64_t src = 0; src < num_vertices; ++src) {
    const size_t degree = index[src + 1] - index[src];
    if (degree > 0) {
      level[src] = 0;
      std::cout << "BFS root: " << src << std::endl;
      return;
    }
  }
  std::cerr << "Can not find a proper root vertex; all vertices do not have any edges?" << std::endl;
  std::abort();
}

void count_level(const size_t num_vertices, const uint16_t max_level, const uint16_t *const level) {

  std::vector<size_t> cnt(max_level + 1, 0);
  for (uint64_t i = 0; i < num_vertices; ++i) {
    if (level[i] == bfs::k_infinite_level) continue;
    if (level[i] > max_level) {
      std::cerr << "Invalid level: " << level[i] << " > " << max_level << std::endl;
      return;
    }
    ++cnt[level[i]];
  }

  std::cout << "Level\t#vertices" << std::endl;
  for (uint16_t i = 0; i <= max_level; ++i) {
    std::cout << i << "\t" << cnt[i] << std::endl;
  }
}

int main(int argc, char **argv) {
  size_t num_vertices;
  size_t num_edges;
  std::string graph_file_name;

  parse_options(argc, argv, num_vertices, num_edges, graph_file_name);

  const uint64_t *index = nullptr;
  const uint64_t *edges = nullptr;
  std::tie(index, edges) = map_graph(num_vertices, num_edges, graph_file_name);

  std::vector<uint16_t> level(num_vertices); // Array to store each vertex's level (a distance from the source vertex)
  std::vector<uint64_t> visited_filter(utility::bitmap_size(num_vertices)); // bitmap data to store 'visited' information

  bfs::init_bfs(num_vertices, level.data(), visited_filter.data());
  find_bfs_root(num_vertices, index, level.data());
  const uint16_t max_level = bfs::run_bfs(num_vertices, index, edges, level.data(), visited_filter.data());

  count_level(num_vertices, max_level, level.data());

  return 0;
}
Includes
File run_random_vector.cpp

Parent directory (median_calculation)

Definition (median_calculation/run_random_vector.cpp)
Program Listing for File run_random_vector.cpp

Return to documentation for file (median_calculation/run_random_vector.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cstdlib>

#ifdef _OPENMP
#include <omp.h>
#endif

#include "../utility/commandline.hpp"
#include "../utility/umap_fits_file.hpp"
#include "torben.hpp"
#include "utility.hpp"
#include "vector.hpp"
#include "../utility/time.hpp"

using pixel_type = float;
constexpr size_t default_num_random_vector = 100000;

class beta_distribution {
 public:
  beta_distribution(double a, double b)
      : m_x_gamma(a, 1.0),
        m_y_gamma(b, 1.0) {}

  template <typename rnd_engine>
  double operator()(rnd_engine &engine) {
    double x = m_x_gamma(engine);
    double y = m_y_gamma(engine);
    return x / (x + y);
  }

 private:
  std::gamma_distribution<> m_x_gamma;
  std::gamma_distribution<> m_y_gamma;
};

std::pair<double, std::vector<std::pair<pixel_type, vector_t>>>
shoot_vector(const median::cube_t<pixel_type> &cube, const std::size_t num_random_vector) {
  // Array to store results of the median calculation
  std::vector<std::pair<pixel_type, vector_t>> result(num_random_vector);

  double total_execution_time = 0.0;

#ifdef _OPENMP
#pragma omp parallel
#endif
  {
#ifdef _OPENMP
    std::mt19937 rnd_engine(123 + omp_get_thread_num());
#else
    std::mt19937 rnd_engine(123);
#endif
    std::uniform_int_distribution<int> x_start_dist(0.2 * cube.size_x, 0.8 * cube.size_x);
    std::uniform_int_distribution<int> y_start_dist(0.2 * cube.size_y, 0.8 * cube.size_y);
    beta_distribution x_beta_dist(3, 2);
    beta_distribution y_beta_dist(3, 2);
    std::discrete_distribution<int> plus_or_minus{-1, 1};

    // Shoot random vectors using multiple threads
#ifdef _OPENMP
#pragma omp for
#endif
    for (int i = 0; i < num_random_vector; ++i) {
      double x_intercept = x_start_dist(rnd_engine);
      double y_intercept = y_start_dist(rnd_engine);

      // Changed to the const value to 2 from 25 so that vectors won't access
      // out of range of the cube with a large number of frames
      //
      // This is a temporary measures
      double x_slope = x_beta_dist(rnd_engine) * plus_or_minus(rnd_engine) * 2;
      double y_slope = y_beta_dist(rnd_engine) * plus_or_minus(rnd_engine) * 2;

      vector_t vector{x_intercept, x_slope, y_intercept, y_slope};

      vector_iterator<pixel_type> begin(cube, vector, 0);
      vector_iterator<pixel_type> end(vector_iterator<pixel_type>::create_end(cube, vector));

      // median calculation using Torben algorithm
      const auto start = utility::elapsed_time_sec();
      result[i].first = torben(begin, end);
      total_execution_time += utility::elapsed_time_sec(start);
      result[i].second = vector;
    }
  }

  return std::make_pair(total_execution_time, result);
}

void print_top_median(const median::cube_t<pixel_type> &cube, std::vector<std::pair<pixel_type, vector_t>> &result) {
  // Sort the results by the descending order of median value
  std::partial_sort(result.begin(),
                    result.begin() + 10, // get only top 10 elements
                    result.end(),
                    [](const std::pair<pixel_type, vector_t> &lhd,
                       const std::pair<pixel_type, vector_t> &rhd) {
                      return (lhd.first > rhd.first);
                    });

  // Print out the top 10 median values and corresponding pixel values
  std::cout << "Top 10 median and corresponding pixel values (NaN values are not used in median calculation)"
            << std::endl;
  std::cout.setf(std::ios::fixed, std::ios::floatfield);
  std::cout.precision(2);
  for (size_t i = 0; i < 10; ++i) {
    const pixel_type median = result[i].first;
    const vector_t vector = result[i].second;
    std::cout << "[" << i << "]"
              << "\n Median: " << median
              << "\n Vector: " << vector.x_slope << " " << vector.x_intercept
              << " " << vector.y_slope << " " << vector.y_intercept << std::endl;

    for (size_t k = 0; k < cube.size_k; ++k) {
      const ssize_t index = get_index(cube, vector, k);
      if (index == -1) continue;
      const pixel_type value = median::reverse_byte_order(cube.data[index]);
      if (median::is_nan(value))
        std::cout << " 'NaN'";
      else
        std::cout << " " << median::reverse_byte_order(cube.data[index]);
    }
    std::cout << std::endl;
  }
}

int main(int argc, char **argv) {
  utility::umt_optstruct_t options;
  umt_getoptions(&options, argc, argv);

#ifdef _OPENMP
  omp_set_num_threads(options.numthreads);
#endif

  size_t BytesPerElement;
  median::cube_t<pixel_type> cube;

  // Alloc memory space and read data from fits files with umap
  cube.data = (pixel_type *)utility::umap_fits_file::PerFits_alloc_cube(
      options.filename, &BytesPerElement, &cube.size_x, &cube.size_y, &cube.size_k);

  if (cube.data == nullptr) {
    std::cerr << "Failed to allocate memory for cube\n";
    std::abort();
  }

  if (sizeof(pixel_type) != BytesPerElement) {
    std::cerr << "Wrong pixel type" << std::endl;
    std::abort();
  }

  const char* buf = std::getenv("NUM_VECTORS");
  std::size_t num_random_vector = default_num_random_vector;
  if (buf != nullptr) {
    num_random_vector = std::stoll(buf);
  }

  auto result = shoot_vector(cube, num_random_vector);
  std::cout << "#of vectors = " << num_random_vector
            << "\nexecution time (sec) = " << result.first
            << "\nvectors/sec = " << static_cast<double>(num_random_vector) / result.first << std::endl;
  print_top_median(cube, result.second);

  utility::umap_fits_file::PerFits_free_cube(cube.data);

  return 0;
}
Includes
File test_bfs.cpp

Parent directory (bfs)

Definition (bfs/test_bfs.cpp)
Program Listing for File test_bfs.cpp

Return to documentation for file (bfs/test_bfs.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <unistd.h>
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
#include <fstream>

#include "bfs_kernel.hpp"
#include "../utility/bitmap.hpp"
#include "../utility/mmap.hpp"

void parse_options(int argc, char **argv,
                   size_t &num_vertices, size_t &num_edges,
                   std::string &graph_file_name,
                   std::string &bfs_level_reference_file_name) {
  num_vertices = 0;
  num_edges = 0;
  graph_file_name = "";
  bfs_level_reference_file_name = "";

  char c;
  while ((c = getopt(argc, argv, "n:m:g:l:h")) != -1) {
    switch (c) {
      case 'n': /// Required
        num_vertices = std::stoull(optarg);
        break;

      case 'm': /// Required
        num_edges = std::stoull(optarg);
        break;

      case 'g': /// Required
        graph_file_name = optarg;
        break;

      case 'l': /// Required
        bfs_level_reference_file_name = optarg;
        break;

      case 'h':
        // usage();
        break;
    }
  }
}

std::pair<uint64_t *, uint64_t *>
map_graph(const size_t num_vertices, const size_t num_edges, const std::string &graph_file_name) {
  const size_t graph_size = (num_vertices + 1 + num_edges) * sizeof(uint64_t);

  int fd = -1;
  void *map_raw_address = nullptr;
  std::tie(fd, map_raw_address) = utility::map_file_read_mode(graph_file_name, nullptr, graph_size, 0);
  if (fd == -1 || map_raw_address == nullptr) {
    std::cerr << "Failed to map the graph" << std::endl;
    std::abort();
  }

  uint64_t *index = static_cast<uint64_t *>(map_raw_address);
  const std::ptrdiff_t edges_offset = num_vertices + 1;
  uint64_t *edges = static_cast<uint64_t *>(map_raw_address) + edges_offset;

  return std::make_pair(index, edges);
}

void validate_level(const std::vector<uint16_t>& level, const std::string& bfs_level_reference_file_name) {

  std::ifstream ifs(bfs_level_reference_file_name);
  if (!ifs.is_open()) {
    std::cerr << "Can not open: "<< bfs_level_reference_file_name << std::endl;
    std::abort();
  }

  std::vector<uint16_t> ref_level(level.size(), bfs::k_infinite_level);
  uint64_t id;
  uint16_t lv;
  while (ifs >> id >> lv) {
    ref_level[id] = lv;
  }

  if (level != ref_level) {
    std::cerr << "BFS level is wrong" << std::endl;
    std::abort();
  }
}

int main(int argc, char **argv) {
  size_t num_vertices;
  size_t num_edges;
  std::string graph_file_name;
  std::string bfs_level_reference_file_name;

  parse_options(argc, argv, num_vertices, num_edges, graph_file_name, bfs_level_reference_file_name);

  const uint64_t *index = nullptr;
  const uint64_t *edges = nullptr;
  std::tie(index, edges) = map_graph(num_vertices, num_edges, graph_file_name);

  std::vector<uint16_t> level(num_vertices); // Array to store each vertex's level (a distance from the source vertex)
  std::vector<uint64_t> visited_filter(utility::bitmap_size(num_vertices)); // bitmap data to store 'visited' information

  bfs::init_bfs(num_vertices, level.data(), visited_filter.data());
  level[0] = 0; // Start from vertex 0
  bfs::run_bfs(num_vertices, index, edges, level.data(), visited_filter.data());
  std::cout << "Finished BFS" << std::endl;

  validate_level(level, bfs_level_reference_file_name);
  std::cout << "Passed validation" << std::endl;

  return 0;
}
Includes
File test_median_calculation.cpp

Parent directory (median_calculation)

Definition (median_calculation/test_median_calculation.cpp)
Program Listing for File test_median_calculation.cpp

Return to documentation for file (median_calculation/test_median_calculation.cpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <iostream>
#include <cmath>

#include "torben.hpp"
#include "utility.hpp"
#include "vector.hpp"
#include "../utility/commandline.hpp"
#include "../utility/umap_fits_file.hpp"

using pixel_type = float;

constexpr size_t num_vectors = 6;
const pixel_type x_intercept[num_vectors] = {1058.2, 1325.606, 1010.564, 829.674, 1390.826, 1091.015};
const pixel_type x_slope[num_vectors] = {3.5, 3.5, 3.5, 3.5, 3.5, 3.5};
const pixel_type y_intercept[num_vectors] = {124, 424, 724, 1024, 1324, 1624};
const pixel_type y_slope[num_vectors] = {0, 0, 0, 0, 0, 0};
const pixel_type correct_median[num_vectors] = {14913.25, 15223.21, 2284.29, 8939.15, 24899.55, 2395.80};


int main(int argc, char** argv)
{
  utility::umt_optstruct_t options;
  umt_getoptions(&options, argc, argv);

  size_t BytesPerElement;
  median::cube_t<float> cube;

  cube.data = (float*)utility::umap_fits_file::PerFits_alloc_cube(
      options.filename, &BytesPerElement, &cube.size_x, &cube.size_y, &cube.size_k);

  for (int i = 0; i < num_vectors; ++i) {
    std::cout << "Vector " << i << std::endl;

    vector_t vector{x_intercept[i], x_slope[i], y_intercept[i], y_slope[i]};
    vector_iterator<pixel_type> begin(cube, vector, 0);
    vector_iterator<pixel_type> end(vector_iterator<pixel_type>::create_end(cube, vector));

    // median calculation w/ Torben algorithm
    const auto median_val = torben(begin, end);

    // Check the result
    std::cout.setf(std::ios::fixed, std::ios::floatfield);
    std::cout.precision(2);
    if (std::fabs(median_val - correct_median[i]) < 0.01) {
      std::cout << " Correct " <<  median_val << " == " << correct_median[i] << std::endl;
    } else {
      std::cerr << " Error " <<  median_val << " != " << correct_median[i] << std::endl;
      std::abort();
    }
  }

  utility::umap_fits_file::PerFits_free_cube(cube.data);

  std::cout << "Passed all tests" << std::endl;

  return 0;
}
Includes
File time.hpp

Parent directory (utility)

Definition (utility/time.hpp)
Program Listing for File time.hpp

Return to documentation for file (utility/time.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef UMAP_TEST_LIB_UTILITY_TIME_HPP
#define UMAP_TEST_LIB_UTILITY_TIME_HPP

#include <chrono>

namespace utility {
inline std::chrono::high_resolution_clock::time_point elapsed_time_sec() {
  return std::chrono::high_resolution_clock::now();
}

inline double elapsed_time_sec(const std::chrono::high_resolution_clock::time_point &tic) {
  auto duration_time = std::chrono::high_resolution_clock::now() - tic;
  return static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(duration_time).count() / 1e6);
}
}
#endif //UMAP_TEST_LIB_UTILITY_TIME_HPP
Includes
  • chrono
Namespaces
File torben.hpp

Parent directory (median_calculation)

Definition (median_calculation/torben.hpp)
Program Listing for File torben.hpp

Return to documentation for file (median_calculation/torben.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
The original code of Torben algorithm is in public domain
Its algorithm is developed by Torben Mogensen and implementated by N. Devillard
This version considerably modified
This implementation also contains the modification proposed in https://github.com/sarnold/medians-1D/issues/8
*/

#ifndef UMAP_TORBEN_HPP
#define UMAP_TORBEN_HPP

#include <algorithm>
#include <iterator>

/*
STL-like Torben algorithm implementation for median calculation
Returns the median value of given elements that are accessible via a random access iterator

\tparam iterator_type Type of the iterator
\param iterator_begin Iterator for the beginning position
\param iterator_end Iterator for the end position
\return Calculated median value. If the size of the array is 0, returns 0.

\example
1) STL container
std::vector<int> vec;
int median = torben(vec.cbegin(), vec.cend());

2) you can also use a normal array
int array[10];
int median = torben(array, array + 10);

3) use your own iterator
own_iterator_class itr_begin;
own_iterator_class itr_end;
int median = torben(itr_begin, itr_end);


class vector_iterator {
 public:
  // Required types to use some stl functions
  using value_type = pixel_type;
  using difference_type = ssize_t;
  using iterator_category = std::random_access_iterator_tag;
  using pointer = value_type *;
  using reference = value_type &;

  // Constructor
  vector_iterator(const median::cube_t<pixel_type> &_cube,
                         const median::vector_t &_vector,
                         const size_t _start_pos)
      : cube(_cube),
        vector(_vector),
        current_pos(_start_pos) {}

  // Copy constructor
  vector_iterator(const vector_iterator&) = default;

  bool operator!=(const vector_iterator &);
  difference_type operator-(const vector_iterator &);
  value_type operator*();
  value_type operator[](size_t);

  // To support
  // ++iterator
  value_type operator++() {
    size_t tmp = current_pos;
    ++current_pos;
    return (*this)[tmp];
  }

  median::cube_t<pixel_type> cube;
  median::vector_t vector;
  size_t current_pos;
};
 */
template <typename iterator_type>
typename iterator_type::value_type
torben(iterator_type iterator_begin, iterator_type iterator_end) {
  using value_type = typename std::iterator_traits<iterator_type>::value_type;

  if (iterator_begin == iterator_end)
    return 0;

  // ---------- Find min and max value over time frame ---------- //
  value_type min = *iterator_begin;
  value_type max = *iterator_begin;
  std::size_t length = 0;
  for (auto iterator(iterator_begin); iterator != iterator_end; ++iterator) {
    const value_type value = *iterator;
    min = std::min(min, value);
    max = std::max(max, value);
    ++length;
  }
  const size_t half = (length + 1) / 2;

  // ---------- Find median value ---------- //
  size_t less, greater, equal;
  value_type guess, maxltguess, mingtguess;
  while (true) {
    guess = (min + max) / 2.0; // Should cast to double before divide?
    less = 0;
    greater = 0;
    equal = 0;
    maxltguess = min;
    mingtguess = max;

    for (auto iterator(iterator_begin); iterator != iterator_end; ++iterator) {
      const value_type value = *iterator;
      if (value < guess) {
        less++;
        if (value > maxltguess) maxltguess = value;
      } else if (value > guess) {
        greater++;
        if (value < mingtguess) mingtguess = value;
      } else {
        equal++;
      }
    }

    if (less <= half && greater <= half) break;
    else if (less > greater) max = maxltguess;
    else min = mingtguess;
  }

  // ----- Calculate a mean value if the number of the given elements is an even number ----- //
  if (less >= half) min = maxltguess;
  else if (less + equal >= half) min = guess;
  else min = mingtguess;

  if (length & 1) return min;

  if (greater >= half) max = mingtguess;
  else if (greater + equal >= half) max = guess;
  else max = maxltguess;

  return (min + max) / 2.0;
}

#endif //UMAP_TORBEN_HPP
Includes
  • algorithm
  • iterator
File umap_file.hpp

Parent directory (utility)

Definition (utility/umap_file.hpp)
Program Listing for File umap_file.hpp

Return to documentation for file (utility/umap_file.hpp)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT
 * file in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _UMAP_FILE_HPP_
#define _UMAP_FILE_HPP_

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <iostream>
#include <string>
#include <sstream>
#include <sys/stat.h>
#include <fcntl.h>
#include "umap/umap.h"

namespace utility {

void* map_in_file(
    std::string filename,
    bool initonly,
    bool noinit,
    bool usemmap,
    uint64_t numbytes)
{
  int o_opts = O_RDWR | O_LARGEFILE | O_DIRECT;
  void* region = NULL;
  int fd;

  if ( initonly || !noinit ) {
    o_opts |= O_CREAT;
    unlink(filename.c_str());   // Remove the file if it exists
  }

  if ( ( fd = open(filename.c_str(), o_opts, S_IRUSR | S_IWUSR) ) == -1 ) {
    std::string estr = "Failed to open/create " + filename + ": ";
    perror(estr.c_str());
    return NULL;
  }

  if ( o_opts & O_CREAT ) {
    // If we are initializing, attempt to pre-allocate disk space for the file.
    try {
      int x;
      if ( ( x = posix_fallocate(fd, 0, numbytes) != 0 ) ) {
        std::ostringstream ss;
        ss << "Failed to pre-allocate " <<
          numbytes << " bytes in " << filename << ": ";
        perror(ss.str().c_str());
        return NULL;
      }
    } catch(const std::exception& e) {
      std::cerr << "posix_fallocate: " << e.what() << std::endl;
      return NULL;
    } catch(...) {
      std::cerr << "posix_fallocate failed to allocate backing store\n";
      return NULL;
    }
  }

  struct stat sbuf;
  if (fstat(fd, &sbuf) == -1) {
    std::string estr = "Failed to get status (fstat) for " + filename + ": ";
    perror(estr.c_str());
    return NULL;
  }

  if ( (off_t)sbuf.st_size != (numbytes) ) {
    std::cerr << filename << " size " << sbuf.st_size
      << " does not match specified data size of " << (numbytes) << std::endl;
    return NULL;
  }

  const int prot = PROT_READ|PROT_WRITE;

  if ( usemmap ) {
    region = mmap(NULL, numbytes, prot, MAP_SHARED | MAP_NORESERVE, fd, 0);
    if (region == MAP_FAILED) {
      std::ostringstream ss;
      ss << "mmap of " << numbytes << " bytes failed for " << filename << ": ";
      perror(ss.str().c_str());
      return NULL;
    }
  }
  else {
    int flags = UMAP_PRIVATE;

    region = umap(NULL, numbytes, prot, flags, fd, 0);
    if ( region == UMAP_FAILED ) {
        std::ostringstream ss;
        ss << "umap_mf of " << numbytes
          << " bytes failed for " << filename << ": ";
        perror(ss.str().c_str());
        return NULL;
    }
  }

  return region;
}

void unmap_file(bool usemmap, uint64_t numbytes, void* region)
{
  if ( usemmap ) {
    if ( munmap(region, numbytes) < 0 ) {
      std::ostringstream ss;
      ss << "munmap failure: ";
      perror(ss.str().c_str());
      exit(-1);
    }
  }
  else {
    if (uunmap(region, numbytes) < 0) {
      std::ostringstream ss;
      ss << "uunmap of failure: ";
      perror(ss.str().c_str());
      exit(-1);
    }
  }
}

}
#endif
Includes
  • fcntl.h
  • iostream
  • sstream
  • string
  • sys/stat.h
  • umap/umap.h
Namespaces
File umap_fits_file.hpp

Parent directory (utility)

Definition (utility/umap_fits_file.hpp)
Program Listing for File umap_fits_file.hpp

Return to documentation for file (utility/umap_fits_file.hpp)

/*
 * This file is part of UMAP.
 *
 * For copyright information see the COPYRIGHT file in the top level
 * directory or at https://github.com/LLNL/umap/blob/master/COPYRIGHT.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (as published by
 * the Free Software Foundation) version 2.1 dated February 1999.
 *
 * This program 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 terms and conditions of 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 program; if not, write to the
 * Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 */
#ifndef _UMAP_PERFITS_H
#define _UMAP_PERFITS_H
#include <ostream>
#include <string>
#include <vector>
#include <stdint.h>
#include <iomanip>
#include <sstream>
#include <cassert>
#include <unordered_map>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "umap/umap.h"
#include "fitsio.h"

#include "../utility/commandline.hpp"
#include "umap/Store.h"

namespace utility {
namespace umap_fits_file {

struct Tile_Dim {
  std::size_t xDim;
  std::size_t yDim;
  std::size_t elem_size;
};

struct Tile_File {
  int fd;
  std::string fname;
  std::size_t tile_start;
  std::size_t tile_size;
};

class Tile {
friend std::ostream &operator<<(std::ostream &os, utility::umap_fits_file::Tile const &ft);
public:
  Tile(const std::string& _fn);
  ssize_t pread(std::size_t alignment, void* cpy_buf, void* buf, std::size_t nbytes, off_t offset);
  Tile_Dim get_Dim() { return dim; }
private:
  Tile_File file;
  Tile_Dim  dim;
};
std::ostream &operator<<(std::ostream &os, utility::umap_fits_file::Tile const &ft);

struct Cube {
  size_t tile_size;  // Size of each tile (assumed to be the same for each tile)
  size_t cube_size;  // Total bytes in cube
  off_t page_size;
  vector<utility::umap_fits_file::Tile> tiles;  // Just one column for now
};

static std::unordered_map<void*, Cube*>  Cubes;

class CfitsStoreFile : public Store {
  public:
    CfitsStoreFile(Cube* _cube_, size_t _rsize_, size_t _alignsize_)
      : cube{_cube_}, rsize{_rsize_}, alignsize{_alignsize_}
    {
      if ( posix_memalign(&alignment_buffer, alignsize, alignsize) ) {
            exit(1);
      }
    }

    ~CfitsStoreFile() {
      free(alignment_buffer);
    }

    ssize_t read_from_store(char* buf, size_t nb, off_t off) {
      ssize_t rval;
      ssize_t bytesread = 0;

      //
      // Now read in remaining bytes
      //
      while ( nb ) {
        off_t tileno = off / cube->tile_size;
        off_t tileoffset = off % cube->tile_size;
        size_t bytes_to_eof = cube->tile_size - tileoffset;
        size_t bytes_to_read = std::min(bytes_to_eof, nb);

        if ( ( rval = cube->tiles[tileno].pread(cube->page_size, alignment_buffer, buf, bytes_to_read, tileoffset) ) == -1) {
          perror("ERROR: pread failed");
          exit(1);
        }

        bytesread += rval;
        nb -= rval;
        buf += rval;
        off += rval;
      }

      return bytesread;
    }

    ssize_t  write_to_store(char* buf, size_t nb, off_t off) {
      assert("FITS write not supported" && 0);
      return 0;
    }

    void* region;

  private:
    Cube* cube;
    void* alignment_buffer;
    size_t rsize;
    size_t alignsize;
    int fd;
};

/* Returns pointer to cube[Z][Y][X] Z=time, X/Y=2D space coordinates */
void* PerFits_alloc_cube(
    string name,
    size_t* BytesPerElement,            /* Output: size of each element of cube */
    size_t* xDim,                       /* Output: Dimension of X */
    size_t* yDim,                       /* Output: Dimension of Y */
    size_t* zDim                        /* Output: Dimension of Z */
)
{
  void* region = NULL;

  Cube* cube = new Cube{.tile_size = 0, .cube_size = 0};
  cube->page_size = utility::umt_getpagesize();
  string basename(name);

  *xDim = *yDim = *BytesPerElement = 0;
  for (int i = 1; ; ++i) {
    std::stringstream ss;
    ss << basename << i << ".fits";
    struct stat sbuf;

    if ( stat(ss.str().c_str(), &sbuf) == -1 ) {
      if ( i == 1 ) {
        cerr << "File: " << ss.str() << " does not exist\n";
        return region;
      }
      break;
    }
    utility::umap_fits_file::Tile T( ss.str() );
    ss.str(""); ss.clear();

    ss << T << endl;

    utility::umap_fits_file::Tile_Dim dim = T.get_Dim();
    if ( *BytesPerElement == 0 ) {
      *xDim = dim.xDim;
      *yDim = dim.yDim;
      *BytesPerElement = dim.elem_size;
      cube->tile_size = (dim.xDim * dim.yDim * dim.elem_size);
    }
    else {
      assert( *xDim == dim.xDim && *yDim == dim.yDim && *BytesPerElement == dim.elem_size );
    }
    *zDim = i;

    cube->cube_size += cube->tile_size;

    cube->tiles.push_back(T);
  }

  // Make sure that our cube is padded if necessary to be page aligned

  size_t psize = utility::umt_getpagesize();
  long remainder = cube->cube_size % psize;

  cube->cube_size += remainder ? (psize - remainder) : 0;


  CfitsStoreFile* cstore;
  cstore = new CfitsStoreFile{cube, cube->cube_size, psize};

  const int prot = PROT_READ|PROT_WRITE;
  int flags = UMAP_PRIVATE;

  cstore->region = umap_ex(NULL, cube->cube_size, prot, flags, 0, 0, cstore);
  if ( cstore->region == UMAP_FAILED ) {
      ostringstream ss;
      ss << "umap of " << cube->cube_size << " bytes failed for Cube";
      perror(ss.str().c_str());
      return NULL;
  }

  Cubes[cstore->region] = cube;
  return cstore->region;
}

void PerFits_free_cube(void* region)
{
  auto it = Cubes.find(region);
  assert( "free_cube: failed to find control object" && it != Cubes.end() );
  Cube* cube = it->second;

  if (uunmap(region, cube->cube_size) < 0) {
    ostringstream ss;
    ss << "uunmap of " << cube->cube_size << " bytes failed on region " << region << ": ";
    perror(ss.str().c_str());
    exit(-1);
  }

  delete cube;

  Cubes.erase(region);
}

Tile::Tile(const std::string& _fn)
{
  fitsfile* fptr = NULL;
  int status = 0;
  LONGLONG headstart;
  LONGLONG datastart;
  LONGLONG dataend;
  int bitpix;
  long naxis[2];
  int naxes;
  int open_flags = (O_RDONLY | O_LARGEFILE | O_DIRECT);

  file.fname = _fn;
  file.tile_start = (size_t)0;
  file.tile_size = (size_t)0;
  dim.xDim = (size_t)0;
  dim.yDim = (size_t)0;
  dim.elem_size = 0;
  file.fd = -1;

  if ( fits_open_data(&fptr, file.fname.c_str(), READONLY, &status) ) {
    fits_report_error(stderr, status);
    exit(-1);
  }

  if ( fits_get_hduaddrll(fptr, &headstart, &datastart, &dataend, &status) ) {
    fits_report_error(stderr, status);
    exit(-1);
  }

  if ( fits_get_img_type(fptr, &bitpix, &status) ) {
    fits_report_error(stderr, status);
    exit(-1);
  }

  if ( fits_get_img_param(fptr, 2, &bitpix, &naxes, &naxis[0], &status) ) {
    fits_report_error(stderr, status);
    exit(-1);
  }

  if ( fits_close_file(fptr, &status) ) {
    fits_report_error(stderr, status);
    exit(-1);
  }

  if ( ( file.fd = open(file.fname.c_str(), open_flags) ) == -1 ) {
    perror(file.fname.c_str());
    exit(-1);
  }

  dim.xDim = (size_t)naxis[0];
  dim.yDim = (size_t)naxis[1];
  dim.elem_size = bitpix < 0 ? (size_t)( ( bitpix * -1 ) / 8 ) : (size_t)( bitpix / 8 );
  file.tile_start = (size_t)datastart;
  file.tile_size = (size_t)(dim.xDim * dim.yDim * dim.elem_size);

  assert( (dataend - datastart) >= (dim.xDim * dim.yDim * dim.elem_size) );
}

ssize_t Tile::pread(std::size_t alignment, void* cpy_buf, void* buf, std::size_t nbytes, off_t offset)
{
  std::size_t rval;

  offset += file.tile_start;  // Skip to data portion of file
  off_t unaligned_amount = offset & (alignment - 1);
  offset -= unaligned_amount;
  char* tbuf = (char*)cpy_buf;

  if ( ( rval = ::pread(file.fd, tbuf, alignment, offset) ) == -1) {
    perror("ERROR: pread failed");
    exit(1);
  }

  ssize_t amount_to_copy = std::min(rval, nbytes) - unaligned_amount;

  memcpy(buf, &tbuf[unaligned_amount], amount_to_copy);

  return amount_to_copy;
}

std::ostream &operator<<(std::ostream &os, Tile const &ft)
{
  os << ft.file.fname << " "
     << "Start=" << ft.file.tile_start << ", "
     << "Size=" << ft.file.tile_size << ", "
     << "XDim=" << ft.dim.xDim << ", "
     << "YDim=" << ft.dim.yDim << ", "
     << "ESize=" << ft.dim.elem_size << " ";

  return os;
}
}
}
#endif
Includes
  • ../utility/commandline.hpp
  • algorithm
  • cassert
  • fcntl.h
  • fitsio.h
  • iomanip
  • ostream
  • sstream
  • stdint.h
  • stdlib.h
  • string
  • string.h
  • sys/stat.h
  • sys/types.h
  • umap/Store.h
  • umap/umap.h
  • unistd.h
  • unordered_map
  • vector (File run_random_vector.cpp)
File umapcpu.cpp

Parent directory (umapcpu)

Definition (umapcpu/umapcpu.cpp)
Program Listing for File umapcpu.cpp

Return to documentation for file (umapcpu/umapcpu.cpp)

/*
 * This file is part of UMAP.  For copyright information see the COPYRIGHT file
 * in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>
#include <random>
#include <algorithm>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>    // optind
#include <errno.h>
#include <utmpx.h>
#include <parallel/algorithm>

#ifdef _OPENMP
#include <omp.h>
#endif

#include "umap/umap.h"
#include "../utility/commandline.hpp"
#include "../utility/umap_file.hpp"

#define handle_error_en(en, msg) \
  do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

void cpu_setcpu(int cpu)
{
  int s;
  cpu_set_t cpuset;
  pthread_t thread;

  thread = pthread_self();

  CPU_ZERO(&cpuset);
  CPU_SET(cpu, &cpuset);

  s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  if (s != 0)
    handle_error_en(s, "pthread_setaffinity_np");

  /* Check the actual affinity mask assigned to the thread */

  s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  if (s != 0)
    handle_error_en(s, "pthread_getaffinity_np");
}
static inline uint64_t getns(void)
{
  struct timespec ts;
  int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  assert(ret == 0);
  return (((uint64_t)ts.tv_sec) * 1000000000ULL) + ts.tv_nsec;
}

void initdata(uint64_t *region, int64_t rlen) {
  fprintf(stdout, "initdata: %p, %ld\n", region, rlen);
#pragma omp parallel for
  for(int64_t i=0; i< rlen; ++i) {
    region[i] = (uint64_t) (rlen - i);
  }
}

int main(int argc, char **argv)
{
  utility::umt_optstruct_t options;
  long pagesize;
  int64_t totalbytes;
  uint64_t arraysize;
  void* base_addr;
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<int> rnd_int(0, 39);

  pagesize = utility::umt_getpagesize();

  umt_getoptions(&options, argc, argv);

  omp_set_num_threads(options.numthreads);

  totalbytes = options.numpages*pagesize;
  base_addr = utility::map_in_file(options.filename, options.initonly,
      options.noinit, options.usemmap, totalbytes);
  assert(base_addr != NULL);

  fprintf(stdout, "%lu pages, %lu threads\n", options.numpages, options.numthreads);

  uint64_t *arr = (uint64_t *) base_addr;
  arraysize = totalbytes/sizeof(int64_t);

  uint64_t start = getns();
  if ( !options.noinit ) {
    // init data
    initdata(arr, arraysize);
    fprintf(stdout, "Init took %f us\n", (double)(getns() - start)/1000000.0);
  }

  const int testpages = 400;

  if ( !options.initonly )
  {
    std::vector<int> cpus{0, 10, 20, 30};

    start = getns();
#pragma omp parallel for
    for (uint64_t page = 0; page < options.numpages - testpages; page += testpages) {
      uint64_t sum = 0;

      //cpu_setcpu(10);
      for (int x = 0; x < testpages; x++) {
        uint64_t* p = &arr[(page+x)*(pagesize/sizeof(uint64_t*))];
        sum += *p;
      }

      cpu_setcpu(rnd_int(gen));

      //cpu_setcpu(30);
      for (int x = 0; x < testpages; ++x) {
        uint64_t* p = &arr[(page+x)*(pagesize/sizeof(uint64_t*))];
        *p = sum;
      }
    }

    fprintf(stdout, "test took %f us\n", (double)(getns() - start)/1000000.0);
  }

  utility::unmap_file(options.usemmap, totalbytes, base_addr);

  return 0;
}
Includes
  • ../utility/commandline.hpp
  • ../utility/umap_file.hpp
  • algorithm
  • assert.h
  • errno.h
  • fcntl.h
  • iostream
  • parallel/algorithm
  • pthread.h
  • random (File run_random_vector.cpp)
  • stdint.h
  • stdio.h
  • stdlib.h
  • string.h
  • sys/ioctl.h
  • sys/mman.h
  • sys/stat.h
  • sys/time.h
  • sys/types.h
  • umap/umap.h
  • unistd.h
  • utmpx.h
File umapsort.cpp

Parent directory (umapsort)

Definition (umapsort/umapsort.cpp)
Program Listing for File umapsort.cpp

Return to documentation for file (umapsort/umapsort.cpp)

/* This file is part of UMAP.  For copyright information see the COPYRIGHT
 * file in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT. This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>
#include <random>
#include <string>
#include <vector>
#include <parallel/algorithm>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <omp.h>

#include "umap/umap.h"
#include "../utility/commandline.hpp"
#include "../utility/umap_file.hpp"

using namespace std;

bool sort_ascending = true;

static inline uint64_t getns(void)
{
  struct timespec ts;
  int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  assert(ret == 0);
  return (((uint64_t)ts.tv_sec) * 1000000000ULL) + ts.tv_nsec;
}

void initdata(uint64_t *region, uint64_t rlen) {
  fprintf(stdout, "initdata: %p, %llu\n", region, rlen);
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<uint64_t> rnd_int;
#pragma omp parallel for
  for(uint64_t i=0; i < rlen; ++i) {
    region[i] = (uint64_t) (rlen - i);
  }
}

void validatedata(uint64_t *region, uint64_t rlen) {
  if (sort_ascending == true) {
#pragma omp parallel for
    for(uint64_t i = 0; i < rlen; ++i) {
        if (region[i] != (i+1)) {
            fprintf(stderr, "Worker %d found an error at index %lu, %lu != lt %lu!\n",
                            omp_get_thread_num(), i, region[i], i+1);

            if (i < 3) {
                fprintf(stderr, "Context ");
                for (int j=0; j < 7; j++) {
                    fprintf(stderr, "%lu ", region[j]);
                }
                fprintf(stderr, "\n");
            }
            else if (i > (rlen-4)) {
                fprintf(stderr, "Context ");
                for (uint64_t j=rlen-8; j < rlen; j++) {
                    fprintf(stderr, "%lu ", region[j]);
                }
                fprintf(stderr, "\n");
            }
            else {
                fprintf(stderr,
                    "Context i-3 i-2 i-1 i i+1 i+2 i+3:%lu %lu %lu %lu %lu %lu %lu\n",
                    region[i-3], region[i-2], region[i-1], region[i], region[i+1], region[i+2], region[i+3]);
            }
        }
    }
  }
  else {
#pragma omp parallel for
    for(uint64_t i = 0; i < rlen; ++i) {
        if(region[i] != (rlen - i)) {
            fprintf(stderr, "Worker %d found an error at index %lu, %lu != %lu!\n",
                            omp_get_thread_num(), i, region[i], (rlen - i));

            if (i < 3) {
                fprintf(stderr, "Context ");
                for (int j=0; j < 7; j++) {
                    fprintf(stderr, "%lu ", region[j]);
                }
                fprintf(stderr, "\n");
            }
            else if (i > (rlen-4)) {
                fprintf(stderr, "Context ");
                for (uint64_t j=rlen-8; j < rlen; j++) {
                    fprintf(stderr, "%lu ", region[j]);
                }
                fprintf(stderr, "\n");
            }
            else {
                fprintf(stderr,
                    "Context i-3 i-2 i-1 i i+1 i+2 i+3:%lu %lu %lu %lu %lu %lu %lu\n",
                    region[i-3], region[i-2], region[i-1], region[i], region[i+1], region[i+2], region[i+3]);
            }
        }
    }
  }
}

void* map_in_file(const utility::umt_optstruct_t* testops, uint64_t numbytes)
{
  void* region = NULL;
  int open_options = O_RDWR | O_LARGEFILE | O_DIRECT;
  int fd;
  string filename(testops->filename);

  if ( testops->initonly || !testops->noinit ) {
    open_options |= O_CREAT;
    unlink(filename.c_str());   // Remove the file if it exists
  }

  if ( ( fd = open(filename.c_str(), open_options, S_IRUSR | S_IWUSR) ) == -1 ) {
    string estr = "Failed to open/create " + filename + ": ";
    perror(estr.c_str());
    return NULL;
  }

  if ( open_options & O_CREAT ) { // If we are initializing, attempt to pre-allocate disk space for the file.
    try {
      int x;
      if ( ( x = posix_fallocate(fd, 0, numbytes) != 0 ) ) {
        ostringstream ss;
        ss << "Failed to pre-allocate " << numbytes << " bytes in " << filename << ": ";
        perror(ss.str().c_str());
        return NULL;
      }
    } catch(const std::exception& e) {
      cerr << "posix_fallocate: " << e.what() << endl;
      return NULL;
    } catch(...) {
      cerr << "posix_fallocate failed to allocate backing store\n";
      return NULL;
    }
  }

  struct stat sbuf;
  if (fstat(fd, &sbuf) == -1) {
    string estr = "Failed to get status (fstat) for " + filename + ": ";
    perror(estr.c_str());
    return NULL;
  }

  if ( (off_t)sbuf.st_size != (numbytes) ) {
    cerr << filename << " size " << sbuf.st_size << " does not match specified data size of " << (numbytes) << endl;
    return NULL;
  }

  const int prot = PROT_READ|PROT_WRITE;

  if ( testops->usemmap ) {
    region = mmap(NULL, numbytes, prot, MAP_SHARED | MAP_NORESERVE, fd, 0);

    if (region == MAP_FAILED) {
      ostringstream ss;
      ss << "mmap of " << numbytes << " bytes failed for " << filename << ": ";
      perror(ss.str().c_str());
      return NULL;
    }
  }
  else {
    int flags = UMAP_PRIVATE;

    region = umap(NULL, numbytes, prot, flags, fd, 0);
    if ( region == UMAP_FAILED ) {
        ostringstream ss;
        ss << "umap_mf of " << numbytes << " bytes failed for " << filename << ": ";
        perror(ss.str().c_str());
        return NULL;
    }
  }

  return region;
}

void unmap_file(const utility::umt_optstruct_t* testops, uint64_t numbytes, void* region)
{
  if ( testops->usemmap ) {
    if ( munmap(region, numbytes) < 0 ) {
      ostringstream ss;
      ss << "munmap failure: ";
      perror(ss.str().c_str());
      exit(-1);
    }
  }
  else {
    if (uunmap(region, numbytes) < 0) {
      ostringstream ss;
      ss << "uunmap of failure: ";
      perror(ss.str().c_str());
      exit(-1);
    }
  }
}

int main(int argc, char **argv)
{
  utility::umt_optstruct_t options;
  uint64_t pagesize;
  uint64_t totalbytes;
  uint64_t arraysize;
  void* base_addr;

  uint64_t start = getns();
  pagesize = (uint64_t)utility::umt_getpagesize();

  umt_getoptions(&options, argc, argv);

  omp_set_num_threads(options.numthreads);

  totalbytes = options.numpages*pagesize;
  base_addr = utility::map_in_file(options.filename, options.initonly, options.noinit, options.usemmap, totalbytes);
  if (base_addr == nullptr)
    return -1;

  fprintf(stdout, "umap INIT took %f seconds\n", (double)(getns() - start)/1000000000.0);
  fprintf(stdout, "%lu pages, %llu bytes, %lu threads\n", options.numpages, totalbytes, options.numthreads);

  uint64_t *arr = (uint64_t *) base_addr;
  arraysize = totalbytes/sizeof(uint64_t);

  start = getns();
  if ( !options.noinit ) {
    // init data
    initdata(arr, arraysize);
    fprintf(stdout, "Init took %f seconds\n", (double)(getns() - start)/1000000000.0);
  }

  if ( !options.initonly )
  {
    start = getns();
    sort_ascending = (arr[0] != 1);

    if (sort_ascending == true) {
      printf("Sorting in Ascending Order\n");
      __gnu_parallel::sort(arr, &arr[arraysize], std::less<uint64_t>(), __gnu_parallel::quicksort_tag());
    }
    else {
      printf("Sorting in Descending Order\n");
      __gnu_parallel::sort(arr, &arr[arraysize], std::greater<uint64_t>(), __gnu_parallel::quicksort_tag());
    }

    fprintf(stdout, "Sort took %f seconds\n", (double)(getns() - start)/1000000000.0);

    start = getns();
    validatedata(arr, arraysize);
    fprintf(stdout, "Validate took %f seconds\n", (double)(getns() - start)/1000000000.0);
  }

  start = getns();
  utility::unmap_file(options.usemmap, totalbytes, base_addr);
  fprintf(stdout, "umap TERM took %f seconds\n", (double)(getns() - start)/1000000000.0);

  return 0;
}
Includes
File utility.hpp

Parent directory (median_calculation)

Definition (median_calculation/utility.hpp)
Program Listing for File utility.hpp

Return to documentation for file (median_calculation/utility.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/// Memo about median calculation
/// x: horizontal dimension of a frame at a certain time point
/// y: vertical dimension of a frame at a certain time point
/// k: time dimension
/// A cube is a set of 'k' frames

#ifndef MEDIAN_CALCULATION_COMMON_HPP
#define MEDIAN_CALCULATION_COMMON_HPP

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>
#include <cfenv>
#include <cassert>

#define MEDIAN_CALCULATION_COLUMN_MAJOR 1
// #define MEDIAN_CALCULATION_VERBOSE_OUT_OF_RANGE

namespace median
{

template <typename _pixel_type>
struct cube_t {
  using pixel_type = _pixel_type;

  size_t size_x;
  size_t size_y;
  size_t size_k;
  pixel_type *data;
};

/// \brief Return frame size
template <typename pixel_type>
inline size_t get_frame_size(const cube_t<pixel_type>& cube)
{
  return cube.size_x * cube.size_y;
}

/// \brief Return cube size
template <typename pixel_type>
inline size_t get_cube_size(const cube_t<pixel_type>& cube)
{
  return cube.size_x * cube.size_y * cube.size_k;
}

/// \brief Returns an index of a 3D coordinate
template <typename pixel_type>
inline ssize_t get_index(const cube_t<pixel_type>& cube, const size_t x, const size_t y, const size_t k)
{
#if MEDIAN_CALCULATION_COLUMN_MAJOR
  const ssize_t frame_index = x + y * cube.size_x;
#else
  const ssize_t frame_index = x * cube.size_y + y;
#endif

  if (get_frame_size(cube) <= frame_index) {
#ifdef MEDIAN_CALCULATION_VERBOSE_OUT_OF_RANGE
    std::cerr << "Frame index is out-of-range: "
              << "(" << x << ", " << y << ") is out of "
              << "(" << cube.size_x << ", " << cube.size_y << ")" << std::endl;
#endif
    return -1;
  }

  const ssize_t cube_index = frame_index + k * get_frame_size(cube);

  if (get_cube_size(cube) <= cube_index) {
#ifdef MEDIAN_CALCULATION_VERBOSE_OUT_OF_RANGE
    std::cerr << "Cube index is out-of-range: "
              << "(" << x << ", " << y << ", " << k << ") is out of "
              << "(" << cube.size_x << ", " << cube.size_y << ", " << cube.size_k << ")" << std::endl;
#endif
    return -1;
  }

  return cube_index;
}

/// \brief Reverses byte order
/// \tparam T Type of value; currently only 4 Byte types are supported
/// \param x Input value
/// \return Given value being reversed byte order
template <typename T>
inline T reverse_byte_order(const T x)
{
  static_assert(sizeof(T) == 4, "T is not a 4 byte of type");
  T reversed_x;
  auto *const p1 = reinterpret_cast<const char *>(&x);
  auto *const p2 = reinterpret_cast<char *>(&reversed_x);
  p2[0] = p1[3];
  p2[1] = p1[2];
  p2[2] = p1[1];
  p2[3] = p1[0];

  return reversed_x;
}

template <typename pixel_type>
bool is_nan(const pixel_type value)
{
  return std::isnan(value);
}

} // namespace median

#endif //MEDIAN_CALCULATION_COMMON_HPP
Includes
  • cassert
  • cfenv
  • cmath
  • fstream
  • iomanip
  • iostream
  • string
Namespaces
File vector.hpp

Parent directory (median_calculation)

Definition (median_calculation/vector.hpp)
Program Listing for File vector.hpp

Return to documentation for file (median_calculation/vector.hpp)

/*
This file is part of UMAP.  For copyright information see the COPYRIGHT
file in the top level directory, or at
https://github.com/LLNL/umap/blob/master/COPYRIGHT
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (as published by the Free
Software Foundation) version 2.1 dated February 1999.  This program 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 terms and conditions of 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


#ifndef UMAP_VECTOR_HPP
#define UMAP_VECTOR_HPP

#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
#include <cassert>

#include "utility.hpp"

struct vector_t
{
  double x_intercept;
  double x_slope;
  double y_intercept;
  double y_slope;
};


/// \brief Returns an index of a 3D coordinate. vector version
template <typename pixel_type>
inline ssize_t get_index(const median::cube_t<pixel_type>& cube, const vector_t& vec, const size_t epoch)
{
  return median::get_index(cube,
                           std::round(vec.x_slope * epoch + vec.x_intercept),
                           std::round(vec.y_slope * epoch + vec.y_intercept),
                           epoch);
}

// Iterator class to use torben function with vector model
// This class is a minimum implementation of an iterator to use the torben function
template <typename pixel_type>
class vector_iterator {
 public:
  // Required types to use some stl functions
  using value_type = pixel_type;
  using difference_type = ssize_t;
  using iterator_category = std::random_access_iterator_tag;
  using pointer = value_type *;
  using reference = value_type &;

  // Constructor
  vector_iterator(const median::cube_t<pixel_type> &_cube,
                  const vector_t &_vector,
                  const size_t _start_pos)
      : cube(_cube),
        vector(_vector),
        current_pos(_start_pos) {
    // Note that when 'end' iterator is given to copy-constructor and MEDIAN_CALCULATION_VERBOSE_OUT_OF_RANGE is ON,
    // this code will trigger the out-of-range error message in get_index() function
    // although passing an 'end' iterator to copy-constructor is an expected behaivor
    if (is_out_of_range(current_pos)) {
      move_to_end();
      return;
    }

    const value_type current_value = *(*this);
    if (median::is_nan(current_value)) {
      move_to_next_valid_position();
    }
  }

  // Use default copy constructor
  vector_iterator(const vector_iterator&) = default;

  // To support
  // iterator1 == iterator2
  bool operator==(const vector_iterator &other) {
    return current_pos == other.current_pos;
  }

  // To support
  // iterator1 != iterator2
  bool operator!=(const vector_iterator &other) {
    return !(*this == other);
  }

  // To support
  // difference_type diff = iterator2 - iterator1
  difference_type operator-(const vector_iterator &other) {
    return current_pos - other.current_pos;
  }

  // To support
  // value_type val = *iterator
  value_type operator*() {
    assert(!is_out_of_range(current_pos)); // for sanitary check
    return median::reverse_byte_order(cube.data[get_index(cube, vector, current_pos)]);
  }

  // To support
  // ++iterator
  vector_iterator& operator++() {
    move_to_next_valid_position();
    return (*this);
  }

  // Utility function returns an iterator object pointing the end
  static vector_iterator create_end(const median::cube_t<pixel_type> &cube, const vector_t &vector) {
    vector_iterator iterator(cube, vector, 0); // 0 is a dummy value
    iterator.move_to_end();
    return iterator;
  }

 private:
  void move_to_next_valid_position() {
    ++current_pos;

    // Skip 'nan' values
    // When the vector is outside of the cube, move to the 'end' position
    while (true) {
      if (cube.size_k <= current_pos) {
        move_to_end();
        break;
      }

      if (is_out_of_range(current_pos)) {
        move_to_end();
        break;
      }

      const value_type current_value = *(*this);
      if (!median::is_nan(current_value)) {
        break; // Found next non-'nan' value
      }

      ++current_pos;
    }
  }

  // move position to the 'end' position
  void move_to_end() {
    current_pos = cube.size_k;
  }

  bool is_out_of_range(const size_t pos) {
    return (get_index(cube, vector, pos) == -1);
  }

  median::cube_t<pixel_type> cube;
  vector_t vector;
  size_t current_pos;
};

#endif //UMAP_VECTOR_HPP
Includes