Code Monkey home page Code Monkey logo

wasm-r3's Introduction

Wasm-R3: Record-Reduce-Replay for Realistic and Standalone WebAssembly Benchmarks

Wasm-R3 is a record and replay framework that enables generation of standalone WebAssembly Benchmarks.

Building the tool

We recommend you consult the wasm-r3.yml workflow file to see the most up-to-date way to build and run the tool.

Pre-built docker images are also provided at doehyunbaek1/wasm-r3, but they are not always updated following the main branch.

As one of the authors regularly run Wasm-R3 on his Arm Mac machine, we are confident Wasm-R3 works well across Linux and Mac.

If you have any problems, please post Github Issue.

Running

npm start <url>
  • <url>: The url of the web app you want to record. Make sure it acutally uses wasm.

The command will start the recording. To stop the recording type any key into the terminal and press enter. The benchmark will be saved to disk.

Testing

npm test <category>

There are three categories of tests:

  • core: These tests the core functionality of Wasm-R3. These tests are basically unit tests.
  • proxy: These tests mainly exercise integration of core Wasm-R3 functionality in the web environments.
  • online: These tests run on real world online web applications in order to confirm which websites are currently supported by Wasm-R3.

The faithfulness of Wasm-R3 is tested by comparing the trace generated during record with the trace generated during replay. The results of the testcases will be generated in the corresponding folders. Interesting files are the report.txt which contains information why a testcase failed. Also the trace for the record and the replay phase gets saved in .r3 files.

Resources

A 15-mintue talk given by one of the authors at Wasm Research Day 2024 is publicly available. You can find a brief discussion of the motivation, approach, and evaluation of Wasm-R3.

A 10-minute demo performed by one of the authors at Wasm Research Day 2024 is publicly available.

You can find a usage walkthorugh of Wasm-R3 and a sneak peak into its inner workings.

Citation

Please refer to Wasm-R3 via our OOPSLA'24 paper:

@inproceedings{Baek2024Wasm-R3,
  title = {Wasm-R3: Record-Reduce-Replay for Realistic and Standalone WebAssembly Benchmarks},
  author = {Baek, Doehyun and Getz, Jakob and Sim, Yusung and Lehmann, Daniel and Titzer, Ben and Ryu, Sukyoung and Pradel, Michael},
  year = {2024},
  booktitle = {Proceedings of the ACM on Programming Languages: Object-Oriented Programming, Systems, Languages \& Applications},
  series = {OOPSLA '24},
}

wasm-r3's People

Contributors

jakobgetz avatar doehyunbaek avatar yusungsim avatar dependabot[bot] avatar

Stargazers

O avatar Steve Manuel avatar  avatar Shrawan P. avatar Arjun Ramesh avatar Max Bernstein avatar Ben L. Titzer avatar Jaehyun Lee avatar  avatar

Watchers

Michael Pradel avatar  avatar  avatar

wasm-r3's Issues

Inconsistent record/replay

Hi developers,

Great tool! I've tried your tool with following code but got inconsistent traces.

use wasm_bindgen::prelude::*;



#[wasm_bindgen(module = "/name.js")]
extern "C" {
    fn name(src: String) -> String;
}

#[wasm_bindgen]
extern "C" {
    // Use `js_namespace` here to bind `console.log(..)` instead of just
    // `log(..)`
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);

    // The `console.log` is quite polymorphic, so we can bind it with multiple
    // signatures. Note that we need to use `js_name` to ensure we always call
    // `log` in JS.
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn log_u32(a: u32);

    // Multiple arguments too!
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn log_many(a: &str, b: &str);
}


 #[wasm_bindgen]
pub fn greet(a: &str) -> String {
    let res = format!("Hello, {}!", name(a.to_string()));
    log(&res);
    res
}
import init, { create, process, math, greet } from './pkg/demo.js';

async function run() {
    await init();

    console.log(greet("Hello"));
    console.log(greet("World"));
}


run();

I got following traces:

[Expected]
IF;0;wbg;__wbg_name_3abd14ecb7c22373
IF;1;wbg;__wbg_log_24dc0bd9d833d95d
EC;45;__wbindgen_add_to_stack_pointer;-16
ER
EC;24;__wbindgen_malloc;5,1
ER
EC;11;greet;1048560,1114120,5
L;0;memory;1114120;72
L;0;memory;1114121;101
L;0;memory;1114122;108
L;0;memory;1114123;108
L;0;memory;1114124;111
IC;0;__wbg_name_3abd14ecb7c22373
EC;24;__wbindgen_malloc;9,1
EC;33;__wbindgen_free;1114136,5,1
IR;0;__wbg_name_3abd14ecb7c22373;
L;0;memory;1048500;9
L;0;memory;1048496;40
L;0;memory;1048498;17
L;0;memory;1114152;72
L;0;memory;1114153;101
L;0;memory;1114154;108
L;0;memory;1114155;108
L;0;memory;1114156;111
L;0;memory;1114157;82
L;0;memory;1114158;117
L;0;memory;1114159;115
L;0;memory;1114160;116
IC;1;__wbg_log_24dc0bd9d833d95d
IR;1;__wbg_log_24dc0bd9d833d95d;
ER
EC;45;__wbindgen_add_to_stack_pointer;16
ER
EC;33;__wbindgen_free;1114168,17,1
ER
EC;45;__wbindgen_add_to_stack_pointer;-16
ER
EC;24;__wbindgen_malloc;5,1
ER
EC;11;greet;1048560,1114120,5
L;0;memory;1114120;87
L;0;memory;1114121;111
L;0;memory;1114122;114
L;0;memory;1114123;108
L;0;memory;1114124;100
IC;0;__wbg_name_3abd14ecb7c22373
EC;24;__wbindgen_malloc;9,1
EC;33;__wbindgen_free;1114136,5,1
IR;0;__wbg_name_3abd14ecb7c22373;
L;0;memory;1114152;87
L;0;memory;1114153;111
L;0;memory;1114154;114
L;0;memory;1114156;100
L;0;memory;1114160;116
IC;1;__wbg_log_24dc0bd9d833d95d
IR;1;__wbg_log_24dc0bd9d833d95d;
ER
EC;45;__wbindgen_add_to_stack_pointer;16
ER
EC;33;__wbindgen_free;1114168,17,1
ER

[Actual]
IF;0;wbg;__wbg_name_3abd14ecb7c22373
IF;1;wbg;__wbg_log_24dc0bd9d833d95d
EC;45;__wbindgen_add_to_stack_pointer;-16
ER
EC;24;__wbindgen_malloc;5,1
ER
EC;11;greet;1048560,1114120,5
L;0;memory;1114120;72
L;0;memory;1114121;101
L;0;memory;1114122;108
L;0;memory;1114123;108
L;0;memory;1114124;111
IC;0;__wbg_name_3abd14ecb7c22373
EC;24;__wbindgen_malloc;9,1
EC;33;__wbindgen_free;1114136,5,1
IR;0;__wbg_name_3abd14ecb7c22373;
L;0;memory;1048500;9
L;0;memory;1048496;40
L;0;memory;1048498;17
L;0;memory;1114152;72
L;0;memory;1114153;101
L;0;memory;1114154;108
L;0;memory;1114155;108
L;0;memory;1114156;111
L;0;memory;1114157;82
L;0;memory;1114158;117
L;0;memory;1114159;115
L;0;memory;1114160;116
IC;1;__wbg_log_24dc0bd9d833d95d
IR;1;__wbg_log_24dc0bd9d833d95d;
ER
EC;45;__wbindgen_add_to_stack_pointer;16
ER
EC;33;__wbindgen_free;1114168,17,1
ER
EC;45;__wbindgen_add_to_stack_pointer;-16
ER
EC;24;__wbindgen_malloc;5,1
ER
EC;11;greet;1048560,1114120,5
IC;0;__wbg_name_3abd14ecb7c22373
EC;24;__wbindgen_malloc;9,1
EC;33;__wbindgen_free;1114136,5,1
IR;0;__wbg_name_3abd14ecb7c22373;
L;0;memory;1114152;87
L;0;memory;1114153;111
L;0;memory;1114154;114
L;0;memory;1114156;100
L;0;memory;1114160;116
IC;1;__wbg_log_24dc0bd9d833d95d
IR;1;__wbg_log_24dc0bd9d833d95d;
ER
EC;45;__wbindgen_add_to_stack_pointer;16
ER
EC;33;__wbindgen_free;1114168,17,1
ER

If seems that the generator put the second memory load world in the wrong location.

import fs from 'fs'
import path from 'path'
let instance
let imports = {}
imports['wbg'] = {}
let global_0 = -1
imports['wbg']['__wbg_name_3abd14ecb7c22373'] = () => {
global_0++
switch (global_0) {
case 0:
instance.exports.__wbindgen_malloc(9,1)
instance.exports.__wbindgen_free(1114136,5,1)
new Uint8Array(instance.exports.memory.buffer)[1048500] = 9
new Uint8Array(instance.exports.memory.buffer)[1048496] = 40
new Uint8Array(instance.exports.memory.buffer)[1048498] = 17
new Uint8Array(instance.exports.memory.buffer)[1114152] = 72
new Uint8Array(instance.exports.memory.buffer)[1114153] = 101
new Uint8Array(instance.exports.memory.buffer)[1114154] = 108
new Uint8Array(instance.exports.memory.buffer)[1114155] = 108
new Uint8Array(instance.exports.memory.buffer)[1114156] = 111
new Uint8Array(instance.exports.memory.buffer)[1114157] = 82
new Uint8Array(instance.exports.memory.buffer)[1114158] = 117
new Uint8Array(instance.exports.memory.buffer)[1114159] = 115
new Uint8Array(instance.exports.memory.buffer)[1114160] = 116
break
case 1:
instance.exports.__wbindgen_malloc(9,1)
instance.exports.__wbindgen_free(1114136,5,1)
new Uint8Array(instance.exports.memory.buffer)[1114152] = 87
new Uint8Array(instance.exports.memory.buffer)[1114153] = 111
new Uint8Array(instance.exports.memory.buffer)[1114154] = 114
new Uint8Array(instance.exports.memory.buffer)[1114156] = 100
new Uint8Array(instance.exports.memory.buffer)[1114160] = 116
break
}
if ((global_0 >= 0) && global_0 < 2) {
return undefined }
}
let global_1 = -1
imports['wbg']['__wbg_log_24dc0bd9d833d95d'] = () => {
global_1++
switch (global_1) {
case 0:
// THIS SECTION IS IN THE WRONG LOCATION
new Uint8Array(instance.exports.memory.buffer)[1114120] = 87
new Uint8Array(instance.exports.memory.buffer)[1114121] = 111
new Uint8Array(instance.exports.memory.buffer)[1114122] = 114
new Uint8Array(instance.exports.memory.buffer)[1114123] = 108
new Uint8Array(instance.exports.memory.buffer)[1114124] = 100
// THIS SECTION IS IN THE WRONG LOCATION
break
}
if ((global_1 >= 0) && global_1 < 2) {
return undefined }
}
export function replay(wasm) {instance = wasm.instance
instance.exports.__wbindgen_add_to_stack_pointer(-16)
instance.exports.__wbindgen_malloc(5,1)
new Uint8Array(instance.exports.memory.buffer)[1114120] = 72
new Uint8Array(instance.exports.memory.buffer)[1114121] = 101
new Uint8Array(instance.exports.memory.buffer)[1114122] = 108
new Uint8Array(instance.exports.memory.buffer)[1114123] = 108
new Uint8Array(instance.exports.memory.buffer)[1114124] = 111
instance.exports.greet(1048560,1114120,5)
instance.exports.__wbindgen_add_to_stack_pointer(16)
instance.exports.__wbindgen_free(1114168,17,1)
instance.exports.__wbindgen_add_to_stack_pointer(-16)
instance.exports.__wbindgen_malloc(5,1)
instance.exports.greet(1048560,1114120,5)
instance.exports.__wbindgen_add_to_stack_pointer(16)
instance.exports.__wbindgen_free(1114168,17,1)
}
export function instantiate(wasmBinary) {
return WebAssembly.instantiate(wasmBinary, imports)
}
if (process.argv[2] === 'run') {
const p = path.join(path.dirname(import.meta.url).replace(/^file:/, ''), 'index.wasm')
const wasmBinary = fs.readFileSync(p)
instantiate(wasmBinary).then((wasm) => replay(wasm))
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.