Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

namandixit/gazelle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gazelle

User-space resource isolation for Serverless

Gazelle is a resource-isolation engine that provides lightweight in-process resource isolation for Serverless applications, to be usable in contexts such as Edge computing on low-power hardware. Specifically, this solution should be able to isolate CPU usage, memory usage and network traffic of different functions running inside the same process.

Read the doc/01. Gazelle Pitch.pdf for the initial pitch, and doc/07. MTP-2 Report.pdf to gain a overview of how Gazelle works.

Compiling

  1. Install Ubuntu 20.04

  2. In the file /etc/apt/sources.list, add the following line at the bottom:

     deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main
    
  3. Run the following commands:

     sudo apt update
     sudo apt upgrade
     sudo apt install llvm-13-dev clang-13 libclang-13-dev
    
  4. Clone the repository

  5. Run the build.linux shell script in the repository root.

Running

  1. To start Gazelle, run the following command:

     ./bin/linux/x64/gazelle ./bin/linux/x64/gazelle_llvm.so ./bin/linux/x64/gazelle_lua.so
    

    Here, ./bin/linux/x64/gazelle is the Gazelle binary, and ./bin/linux/x64/gazelle_llvm.so and ./bin/linux/x64/gazelle_lua.so are the language plugins of LLVM and Lua respectively.

  2. Deploy a function by running:

     ./bin/linux/x64/gazelle_dispatcher_socket_deploy llvm demo.c test/llvm/demo.c
    

    Here, ./bin/linux/x64/gazelle_dispatcher_socket_deploy is the tool used to deploy functions in Gazelle, llvm is the name of the language (provided to Gazelle when the p is loaded), demo.c is the name with which Gazelle should identify this function, and test/llvm/demo.c is the file path where the function is actually stored.

  3. Execute the function with:

     ./bin/linux/x64/gazelle_dispatcher_socket_execute_1 demo.c 100
    

    Here, ./bin/linux/x64/gazelle_dispatcher_socket_execute_1 is the tool used to send execution requests to Gazelle, demo.c is the name of the function that was registered with Gazelle when deploying the function, and 100 is the arguement of the function with which it should be executed.

    If you want to execute more than one instance of function simultaneously, use:

     ./bin/linux/x64/gazelle_dispatcher_socket_execute_n demo.c 10 100
    

    This will send an execution request to execute 10 instances of the same function together.

  4. Send CTRL-C to Gazelle when done.

Directory Structure

  • doc: Contains various slides and reports that document the working of Gazelle.
  • src: Source Code of Gazelle
    • experiments: These C source files are used to run the benchmarking experiments. Details are covered later.
    • languages: This contains the language plugins of Gazelle. Currently implemented plugins are LLVM, Lua, and SM (a simple stack machine interpreter)
    • libraries: First and third party libraries used in Gazelle
      • dlmalloc: Doug Lea's memory allocator (used for memory isolation)
      • libkhadi: The Fiber implementation was pulled into its own library to make it easier to use in any other project
      • lua: Lua 5.4 language runtime
    • platforms: The actual Gazelle implementation
      • linux: Implementation for Linux (currently the only one)
        • dispatchers: The socket-based tools used to deploy and execute functions in the Gazelle process
        • dispatcher_support: Wrapper functions around the Socket communication that is used to deploy and execute functions in Gazelle
  • test: Serverless functions that are deployed and executed on Gazelle
    • llvm: C functions for LLVM
    • lua: Lua functions
    • sm: Stack machine functions

Source Code Reading Guide

  1. Before reading the source code, read the MTP-2 report. It covers all the basic pre-requisite information needed to understand the implmenetation of Gazelle.

  2. To gain familiarity with the idea of fibers, watch this presentation. Then, read up the file libraries/libkhadi/libkhadi.c to see an implementation of a Fiber-based job system similar to the one described in the video. The data structures used in this file (and in the rest of the Gazelle) such as a Dynamic Array, Hash Table, Map, Queue, etc. are implemented in nlib.h.

  3. Then, read gazelle_api.h. The functions and data types defined in this file are used by the language plugin and the Gazelle process to talk to one another.

  4. Next, read the languages/sm plugin. This backed was written in the early days of Gazelle and it doesn't use all the features that were added later. However, it is extremely simple and will provide a easy-to-understand example of how language plugins work.

  5. Now, start reading the implementation of the Gazelle process. Start with platforms/linux/linux.c and read files one by one. Feel free to ignore the parts related to profiling and benchmarking for now; however, if you really want to understand it, the profiling API is implemented in nlib.h using perf_event_open.

  6. Once you understand how Gazelle works, read the Lua plugin (languages/lua). This is a much more complex example and uses Lua APIs. Make sure to copiously consult the Lua 5.4 Manual.

  7. Finally, read the LLVM plugin (languages/llvm). This is the most complicated code, especially since LLVM has a very poorly documented API. Make sure to refer to the relevant documents in the doc folder (1, 2, 3, 4) to understand what the code is actually doing. In short,

    • GazelleJIT class is used to compile the LLVM IR into machine code, and to resolve external symbols.
    • All the LLVM IR patching happens in the FuncModifier struct. The main function here is runOnFunction that is executed on every function in the LLVM module.
    • Rest of the code is mostly just bureaucracy to get LLVM to properly use these two classes.

    While the API documentation for LLVM is very anemic, there is a pretty good tutorial. If understanding how the LLVM plugin is hard, try to work through this tutorial.

Benchmarking

All the experiments are completely automated, and can be run with a single command. When you run build.linux to build the project, it build three special executables: experiment_docker, experiment_process and experiment_gazelle (from the files experiments/docker.c, experiments/process.c and experiments/gazelle.c respectively).

In order to run the benchmarks with a particular isolation backend, simply run its respective executable in the repository's root directory. The experiment will run to completion (unless your machine runs out of resources and the OS freezes/crashes), and will produce a text file called experiment-XYZ-output.txt (where XYZ will be either docker, process or gazelle). This file will contain the results of all the experiments conducted.

The C files in which these experiments are implemented are pretty simple to understand, and they mostly behave like Shell scripts (meaning their job is to start and stop processes, check return values, find how long it took something to run, execute various commands, etc.). The reason C was used instead of Bash is to get access to 64-bit integers for timestamps, and being able to use data structures like Dynamic Arrays.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published