Getting Started¶
This page provides information on how to quickly get up and running with mp-umap.
Dependencies¶
At a minimum, cmake 3.5.1 or greater is required for building mp-umap.
MP-UMAP Build and Installation¶
MP-Umap provides service and client libraries. The former enables developers to launch mp-umap service that transparently manages the shared UMAP buffer and the client API allows multi-processes to bind/interact with the service thereby enabling shared access to UMAP buffer. The following lines should get you up and running:
$ git clone https://github.com/LLNL/umap.git
$ cd umap
$ git checkout mp_umap_pre_release
$ cmake3 -DCMAKE_BUILD_PREFIX=. -DENABLE_TESTS_LINK_STATIC_UMAP=ON -DCMAKE_INSTALL_PREFIX=../install ..;
$ cmake3 --build . --target install
MP-Umap is an experimental branch of Umap that enables sharing of file-backed Umap buffers to multiple processes. At the moment, this feature is only available in read-only mode. By default, mpumap builds with 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.
MP-Umap install files to the lib, include and bin directories of the
CMAKE_INSTALL_PREFIX.
Basic Usage¶
MP-Umap library provides seperate interfaces for service and client processes.
Service communicate with the client processes through a Unix Domain socket. This can be accomplished by calling the following mpumapd API with UNIX domain socket path as an argument. When this argument is specified NULL, default option of UMAP_SERVER_PATH, which is set to ‘/tmp/umap-server’
void umap_server(
std::string filename
);
A simple mpumap Service looks like the following:
#include "umap/mpumapd.h"
#include <string>
#include <iostream>
int main(int argc, char **argv){
std::string filename;
if(argc < 2){
filename = std::string(UMAP_SERVER_PATH);
std::cout<<"Using default mp-umapd socket path";
std::cout<<"Usage: umap-server <unix socket path>";
}else{
filename = std::string(argv[1]);
}
umap_server(filename.c_str());
return 0;
}
In order for a process to interact with the umap-service client applications interact with target service through the following client API calls defined in mpumapclient.h
/*!
* @function init_umap_client
* @abstract initializes connection with an already running mpumap service
* @param sock_path Path to Unix Domain socket hosted by target
* mpumap service. When a NULL value is passed,
* a default UMAP_SERVER_PATH is used
* @result Exits if it fails to connect to the service.
*/
void init_umap_client(const char *sock_path);
/*!
* @function close_umap_client
* @abstract Closes an already established mpumap service connection
* @result Exits if no service is found to be connected with
*/
void close_umap_client();
/*!
* @function client_umap
* @abstract Functionally equivalent to mmaping a file. Should be called only
* after connection with target umap-service has been established using init_umap_client
* @param filename Full path to the file to be memory mapped
* @param prot At present it only accepts PROT_READ as we serve read-only buffers
* This parameter is to catch instances where users intend to use the buffer
* other than read-only purposes.
* @param flags At present it only accepts MAP_SHARED as these buffers are supposed to
* be shared between multiple processes, which include the mpumap service.
* This is to catch cases where user intends to use it otherwise.
* @param addr non-NULL value is intended for fixed address. Floating address otherwise.
* @result Return NULL on failure. Else return the userspace mapped address
*/
void* client_umap(
const char *filename
, int prot
, int flags
, void *addr
);
/*!
* @function init_umap_client
* @abstract Removes the mapping from the client process' address space.
* @param filename Path to file that has previously been mapped
* by client_umap call.
* @result Return -1 on error, 0 On Success
*/
int client_uunmap(
const char *filename
);
/*
* The following mpumap client API calls provide visibility to mpumap
* service's settings to the client. This allows clients to use these
* values as they deem necessary. These calls need to be called after
* establishing connection with a mpumap service through init_umap_client
* API call.
*/
long umapcfg_get_system_page_size( void );
uint64_t umapcfg_get_max_pages_in_buffer( void );
uint64_t umapcfg_get_umap_page_size( void );
uint64_t umapcfg_get_num_fillers( void );
uint64_t umapcfg_get_num_evictors( void );
int umapcfg_get_evict_low_water_threshold( void );
int umapcfg_get_evict_high_water_threshold( void );
uint64_t umapcfg_get_max_fault_events( void );
Here is a simple mpumap Client application that shows the use of API defined in mpumapclient.h
#include "umap/mpumapclient.h"
#include <unistd.h>
#include <sys/mman.h>
using namespace std;
#include <iostream>
void disp_umap_env_variables() {
std::cout
<< "Environment Variable Configuration (command line arguments obsolete):\n"
<< "UMAP_PAGESIZE - currently: " << umapcfg_get_umap_page_size() << " bytes\n"
<< "UMAP_PAGE_FILLERS - currently: " << umapcfg_get_num_fillers() << " fillers\n"
<< "UMAP_PAGE_EVICTORS - currently: " << umapcfg_get_num_evictors() << " evictors\n"
<< "UMAP_BUFSIZE - currently: " << umapcfg_get_max_pages_in_buffer() << " pages\n"
<< "UMAP_EVICT_LOW_WATER_THRESHOLD - currently: " << umapcfg_get_evict_low_water_threshold() << " percent full\n"
<< "UMAP_EVICT_HIGH_WATER_THRESHOLD - currently: " << umapcfg_get_evict_high_water_threshold()
<< " percent full\n"
<< std::endl;
}
int main(int argc, char *argv[]){
void *mapped_addr, *mapped_addr2;;
char *read_addr, *read_addr2;
bool diff = false;
int i=0;
std::string sock_path, filename1, filename2;
int opt;
char opt_string[] = "c:s:f:";
while((opt = getopt(argc, argv, opt_string)) != -1){
switch (opt) {
case 'c':
sock_path = std::string(optarg);
break;
case 'f':
filename1 = std::string(optarg);
break;
case 's':
filename2 = std::string(optarg);
break;
}
}
if(filename1.empty() || filename2.empty()){
std::cerr<<"Usage: ./umap-client -c <socket_path> -f <file1_name> -s <file2_name>";
exit(-1);
}
if(sock_path.empty()){
sock_path = std::string(UMAP_SERVER_PATH);
}
init_umap_client(sock_path.c_str());
disp_umap_env_variables();
mapped_addr = client_umap(filename1.c_str(), PROT_READ, MAP_SHARED, NULL);
mapped_addr2 = client_umap(filename2.c_str(), PROT_READ, MAP_SHARED, NULL);
char *end_addr = (char *)mapped_addr + 4096*1024;
for(read_addr = (char *)mapped_addr, read_addr2 = (char *)mapped_addr2; read_addr <= end_addr ; read_addr++, read_addr2++ ){
if(*read_addr != *read_addr2){
diff = true;
std::cout<<"Files differ at offset "<<(unsigned long)read_addr - (unsigned long)mapped_addr<<std::endl;
break;
}
}
if(!diff){
std::cout<<"No difference detected at page boundaries"<<std::endl;
}
client_uunmap(filename1.c_str());
client_uunmap(filename2.c_str());
return 0;
}
Note: use -lmpumapd and -lmpumapclient to link service and client apps, respectively.