Skip to content

Commit

Permalink
Native function calibration test code (MystenLabs#3021)
Browse files Browse the repository at this point in the history
* Added natives calibration logic skeleton
  • Loading branch information
oxade authored Jul 7, 2022
1 parent faff2b9 commit 9b116ae
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 1 deletion.
9 changes: 9 additions & 0 deletions crates/sui-framework/sources/event.move
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,13 @@ module sui::event {
// TODO(https://github.com/MystenLabs/sui/issues/19):
// restrict to internal types once we can express this in the ability system
public native fun emit<T: copy + drop>(event: T);

// Cost calibration functions
#[test_only]
public fun calibrate_emit<T: copy + drop>(obj: T) {
emit(obj)
}
#[test_only]
public fun calibrate_emit_nop<T: copy + drop>(_obj: T) {
}
}
27 changes: 27 additions & 0 deletions crates/sui-framework/sources/id.move
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,31 @@ module sui::id {

/// Convert raw bytes into an address
native fun bytes_to_address(bytes: vector<u8>): address;

// Cost calibration functions
#[test_only]
public fun calibrate_bytes_to_address(bytes: vector<u8>) {
bytes_to_address(bytes);
}
#[test_only]
public fun calibrate_bytes_to_address_nop(_bytes: vector<u8>) {
}

#[test_only]
public fun calibrate_get_versioned_id<T: key>(obj: &T) {
get_versioned_id(obj);
}
#[test_only]
public fun calibrate_get_versioned_id_nop<T: key>(_obj: &T) {
}

// TBD

// #[test_only]
// public fun calibrate_delete_id<VersionedID>(id: VersionedID) {
// delete_id(id);
// }
// #[test_only]
// public fun calibrate_delete_id_nop<VersionedID>(_id: VersionedID) {
// }
}
36 changes: 36 additions & 0 deletions crates/sui-framework/sources/transfer.move
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,40 @@ module sui::transfer {

// delete `child_id`, emit a system `DeleteChildObject(child)` event
native fun delete_child_object_internal(child: address, child_id: VersionedID);

// Cost calibration functions
#[test_only]
public fun calibrate_freeze_object<T: key>(obj: T) {
freeze_object(obj)
}
#[test_only]
public fun calibrate_freeze_object_nop<T: key + drop>(_obj: T) {
}

#[test_only]
public fun calibrate_share_object<T: key>(obj: T) {
share_object(obj)
}
#[test_only]
public fun calibrate_share_object_nop<T: key + drop>(_obj: T) {
}

#[test_only]
public fun calibrate_transfer_internal<T: key>(obj: T, recipient: address, to_object: bool) {
transfer_internal(obj, recipient, to_object)
}
#[test_only]
public fun calibrate_transfer_internal_nop<T: key + drop>(_obj: T, _recipient: address, _to_object: bool) {
}

#[test_only]
public fun calibrate_delete_child_object_internal(child: address, child_id: VersionedID) {
delete_child_object_internal(child, child_id)
}

// TBD
// #[test_only]
// public fun calibrate_delete_child_object_internal_nop(_child: address, _child_id: VersionedID) {
// }

}
10 changes: 9 additions & 1 deletion crates/sui-framework/sources/tx_context.move
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,12 @@ module sui::tx_context {
#[test_only]
/// Test-only function for creating a new signer from `signer_address`.
native fun new_signer_from_address(signer_address: address): signer;
}

// Cost calibration functions
#[test_only]
public fun calibrate_derive_id(tx_hash: vector<u8>, ids_created: u64) {
derive_id(tx_hash, ids_created);
}
#[test_only]
public fun calibrate_derive_id_nop(_tx_hash: vector<u8>, _ids_created: u64) {
}}
296 changes: 296 additions & 0 deletions crates/sui-framework/tests/natives_calibration_tests.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0


// This module attemps to find the computational cost of native function by measuring the time
// the native takes to execute.
// Isolating the native function is tricky, so we run two functions with and without the native
// The difference in execution times is the time the native takes
// functions prefixed with __baseline do not have the natives
// Many parts of the code are written in such a way that the bytecode diffs yield exactly the
// native to be isolated

// TBD: Try objects of different sizes in natives

#[test_only]
module sui::NativesCalibrationTests {
use sui::id::{Self, VersionedID};

use sui::test_scenario;
use sui::transfer;
use sui::event;
use sui::tx_context;

// Number of times to run the inner loop of tests
// We set this value to 1 to avoid long running tests
// But normally we want something like 1000000
const NUM_TRIALS: u64 = 1;

// A very basic object to be used in calls
struct ObjectSimple has key, store, drop, copy {
}
// A very basic object which has an VersionedID to be used in calls
struct ObjectWithID has key, store{
id: VersionedID,
}


// =================================================================
// Natives in the `event` module
// =================================================================

// =================================================================
// event::emit
// =================================================================
// This native emits an event given an object
// > Note: this function's execution time depends on the size of the object, however we assume
// > a flat cost for all operations

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_event_emit() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
event::calibrate_emit(obj1);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_event_emit__baseline() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
event::calibrate_emit_nop(obj1);
trials = trials - 1;
}
}


// =================================================================
// Natives in the `transfer` module
// =================================================================

// =================================================================
// transfer::freeze_object
// =================================================================
// This native freezes an object

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_transfer_freeze_object() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
transfer::calibrate_freeze_object(obj1);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_transfer_freeze_object__baseline() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
transfer::calibrate_freeze_object_nop(obj1);
trials = trials - 1;
}
}

// =================================================================
// transfer::share_object
// =================================================================
// This native shares an object

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_transfer_share_object() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
transfer::calibrate_share_object(obj1);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_transfer_share_object__baseline() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let obj1 = ObjectSimple { };
transfer::calibrate_share_object_nop(obj1);
trials = trials - 1;
}
}

// =================================================================
// transfer::transfer_internal
// =================================================================
// This native transfers an object to an address

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_transfer_transfer_internal() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let obj1 = ObjectSimple { };
let addr = @0x0;
let to_object = false;
transfer::calibrate_transfer_internal(obj1, addr, to_object);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_transfer_transfer_internal__baseline() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let obj1 = ObjectSimple { };
let addr = @0x0;
let to_object = false;
transfer::calibrate_transfer_internal_nop(obj1, addr, to_object);
trials = trials - 1;
}
}

// =================================================================
// transfer::delete_child_object_internal
// =================================================================
// TBD


// =================================================================
// Natives in the `id` module
// =================================================================

// =================================================================
// id::bytes_to_address
// =================================================================
// This native converts bytes to addresses

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_id_bytes_to_address() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let bytes = x"3a985da74fe225b2045c172d6bd390bd855f086e";
id::calibrate_bytes_to_address(bytes);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_id_bytes_to_address__baseline() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let bytes = x"3a985da74fe225b2045c172d6bd390bd855f086e";
id::calibrate_bytes_to_address_nop(bytes);
trials = trials - 1;
}
}

// =================================================================
// id::get_versioned_id
// =================================================================
// This native extracts the versioned ID from an object

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_id_get_versioned_id() {
let trials: u64 = NUM_TRIALS;
let sender = @0x0;
let scenario = &mut test_scenario::begin(&sender);

while (trials > 0) {
let obj = ObjectWithID {id: tx_context::new_id(test_scenario::ctx(scenario)) };
id::calibrate_get_versioned_id(&obj);
let ObjectWithID { id } = obj;
id::delete(id);

trials = trials - 1;

}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_id_get_versioned_id__baseline() {
let trials: u64 = NUM_TRIALS;
let sender = @0x0;
let scenario = &mut test_scenario::begin(&sender);

while (trials > 0) {
let obj = ObjectWithID {id: tx_context::new_id(test_scenario::ctx(scenario)) };
id::calibrate_get_versioned_id_nop(&obj);
// This forces an immutable borrow to counter the ImmBorrowLoc in id::get_versioned_id
let _ = &obj;
let ObjectWithID { id } = obj;
id::delete(id);

trials = trials - 1;
}
}


// =================================================================
// Natives in the `tx_context` module
// =================================================================

// =================================================================
// tx_context::derive_id
// =================================================================
// This native derives an ID from an object

// This test function calls the native in a typical manner
#[test]
public entry fun test_calibrate_tx_context_derive_id() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532";
let created_num: u64 = 0;
tx_context::calibrate_derive_id(tx_hash, created_num);
trials = trials - 1;
}
}
// This test function excludes the natives
#[test]
public entry fun test_calibrate_tx_context_derive_id__baseline() {
let trials: u64 = NUM_TRIALS;
while (trials > 0) {
let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532";
let created_num: u64 = 0;
tx_context::calibrate_derive_id_nop(tx_hash, created_num);
trials = trials - 1;
}
}


// =================================================================
// These calibrate the `Pop` bytecode instruction because it is needed
// to calculate the cost of popping unused variables in baseline functions
// =================================================================
#[test]
public entry fun test_calibrate_pop() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
let _k = false;
trials = trials - 1;
}
}
#[test]
public entry fun test_calibrate_pop__baseline() {
let trials: u64 = NUM_TRIALS;

while (trials > 0) {
trials = trials - 1;
}
}

}

0 comments on commit 9b116ae

Please sign in to comment.