Expand description

Lamellar is an investigation of the applicability of the Rust systems programming language for HPC as an alternative to C and C++, with a focus on PGAS approaches.

Lamellar provides several different communication patterns to distributed applications. First, Lamellar allows for sending and executing user defined active messages on remote nodes in a distributed environments. User first implement runtime exported trait (LamellarAM) for their data structures and then call a procedural macro (#[lamellar::am]) on the implementation. The procedural macro procudes all the nescessary code to enable remote execution of the active message.

Lamellar also provides PGAS capabilities through multiple interfaces. The first is a low level interface for constructing memory regions which are readable and writable from remote pes (nodes).

The second is a high-level abstraction of distributed arrays, allowing for distributed iteration and data parallel processing of elements.

Lamellar relies on network providers called Lamellae to perform the transfer of data throughout the system. Currently three such Lamellae exist, one used for single node (single process) development (“local”), , one used for single node (multi-process) development (“shmem”) useful for emulating distributed environments,and another based on the Rust OpenFabrics Interface Transport Layer (ROFI) (https://github.com/pnnl/rofi).

EXAMPLES

Selecting a Lamellae and constructing a lamellar world instance

use lamellar::Backend;
fn main(){
 let mut world = lamellar::LamellarWorldBuilder::new()
        .with_lamellae( Default::default() ) //if "enable-rofi" feature is active default is rofi, otherwise  default is Shmem
        //.with_lamellae( Backend::Rofi ) //explicity set the lamellae backend to rofi, using the provider specified by the LAMELLAR_ROFI_PROVIDER env var ("verbs" or "shm")
        //.with_lamellae( Backend::RofiVerbs ) //explicity set the lamellae backend to rofi, specifying the verbs provider
        //.with_lamellae( Backend::Shmem ) //explicity set the lamellae backend to rofi, specifying the shm provider
        .build();
}

Creating and executing a Registered Active Message

use lamellar::ActiveMessaging;

#[lamellar::AmData(Debug, Clone)]
struct HelloWorld { //the "input data" we are sending with our active message
    my_pe: usize, // "pe" is processing element == a node
}

#[lamellar::am]
impl LamellarAM for HelloWorld {
    fn exec(&self) {
        println!(
            "Hello pe {:?} of {:?}, I'm pe {:?}",
            lamellar::current_pe,
            lamellar::num_pes,
            self.my_pe
        );
    }
}

fn main(){
    let mut world = lamellar::LamellarWorldBuilder::new().build();
    let my_pe = world.my_pe();
    let num_pes = world.num_pes();
    let am = HelloWorld { my_pe: my_pe };
    for pe in 0..num_pes{
        world.exec_am_pe(pe,am.clone()); // explicitly launch on each PE
    }
    world.wait_all(); // wait for all active messages to finish
    world.barrier();  // synchronize with other pes
    let handle = world.exec_all(am.clone()); //also possible to execute on every PE with a single call
    handle.get(); //both exec_all and exec_am_pe return request handles that can be used to access any returned result
}

Creating, initializing, and iterating through a distributed array

use lamellar::array::{DistributedIterator, Distribution, SerialIterator, UnsafeArray};

fn main(){
    let world = lamellar::LamellarWorldBuilder::new().build();
    let my_pe = world.my_pe();
    let block_array = UnsafeArray::<usize>::new(world.team(), ARRAY_LEN, Distribution::Block); //we also support Cyclic distribution.
    block_array.dist_iter_mut().enumerate().for_each(move |elem| *elem = my_pe); //simultaneosuly initialize array accross all pes, each pe only updates its local data
    block_array.wait_all();
    block_array.barrier();
    if my_pe == 0{
        for (i,elem) in block_array.ser_iter().into_iter().enumerate(){ //iterate through entire array on pe 0 (automatically transfering remote data)
            println!("i: {} = {})",i,elem);
        }
    }
}

Modules

Macros

Structs

an abstraction used to group pes into distributed computational units

Represents all the pe’s (processing elements) within a given distributed execution

Lamellar World Builder used for customization

Enums

Traits

Functions

Attribute Macros

Derive Macros