Skip to content

Commit

Permalink
feat: charge event gas
Browse files Browse the repository at this point in the history
This charges the correct event gas and adds a few benchmarks. It also:

1. Tries to remove some variability when recording events by
pre-allocating space.`
2. Validates utf8 up-front, then slices the validated string for better
performance (and easier benchmarking).
  • Loading branch information
Stebalien committed Sep 13, 2023
1 parent afa2549 commit 0978a29
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 201 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion fvm/src/call_manager/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,11 +901,18 @@ where
/// If an actor aborts, the last layer should be discarded (discard_last_layer). This will also
/// throw away any events collected from subcalls (and previously merged, as those subcalls returned
/// normally).
#[derive(Default)]
pub struct EventsAccumulator {
events: Vec<StampedEvent>,
idxs: Vec<usize>,
}
impl Default for EventsAccumulator {
fn default() -> Self {
Self {
events: Vec::with_capacity(128),
idxs: Vec::with_capacity(8),
}
}
}

pub(crate) struct Events {
root: Option<Cid>,
Expand Down
23 changes: 16 additions & 7 deletions fvm/src/gas/price_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,14 @@ lazy_static! {
// TODO(#1817): Per-entry event validation cost. These parameters were benchmarked for the
// EVM but haven't been revisited since revising the API.
event_per_entry: ScalingCost {
flat: Gas::new(1750),
scale: Gas::new(25),
flat: Gas::new(2000),
scale: Gas::new(1400),
},

// TODO(#1817): Cost of validating utf8 (used in event parsing).
utf8_validation: ScalingCost {
flat: Zero::zero(),
scale: Zero::zero(),
flat: Gas::new(500),
scale: Gas::new(16),
},

// Preloaded actor IDs per FIP-0055.
Expand Down Expand Up @@ -627,6 +627,15 @@ impl PriceList {
GasCharge::new("OnHashing", gas, Zero::zero())
}

#[inline]
pub fn on_utf8_validation(&self, len: usize) -> GasCharge {
GasCharge::new(
"OnUtf8Validation",
self.utf8_validation.apply(len),
Zero::zero(),
)
}

/// Returns gas required for computing unsealed sector Cid.
#[inline]
pub fn on_compute_unsealed_sector_cid(
Expand Down Expand Up @@ -966,11 +975,11 @@ impl PriceList {

GasCharge::new(
"OnActorEvent",
// Charge for validation/storing events.
mem + validate_entries + validate_utf8,
// Charge for validation/storing/serializing events.
mem * 2u32 + validate_entries + validate_utf8,
// Charge for forming the AMT and returning the events to the client.
// one copy into the AMT, one copy to the client.
hash + (mem * 2u32),
hash + mem,
)
}

Expand Down
13 changes: 9 additions & 4 deletions fvm/src/kernel/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,11 @@ where
return Err(syscall_error!(IllegalArgument; "total event value lengths exceeded the max size: {} > {MAX_TOTAL_VALUES_LEN}", event_values.len()).into());
}

// We validate utf8 all at once for better performance.
let event_keys = std::str::from_utf8(event_keys)
.context("invalid event key")
.or_illegal_argument()?;

let mut key_offset: usize = 0;
let mut val_offset: usize = 0;

Expand Down Expand Up @@ -1098,10 +1103,6 @@ where
.context("event entry key out of range")
.or_illegal_argument()?;

let key = std::str::from_utf8(key)
.context("invalid event key")
.or_illegal_argument()?;

let value = &event_values
.get(val_offset..val_offset + header.val_len as usize)
.context("event entry value out of range")
Expand All @@ -1125,6 +1126,10 @@ where
let actor_evt = ActorEvent::from(entries);

let stamped_evt = StampedEvent::new(self.actor_id, actor_evt);
// Enable this when performing gas calibration to measure the cost of serializing early.
#[cfg(feature = "gas_calibration")]
let _ = fvm_ipld_encoding::to_vec(&stamped_evt).unwrap();

self.call_manager.append_event(stamped_evt);

t.stop();
Expand Down
13 changes: 3 additions & 10 deletions testing/calibration/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum Method {
OnRecoverSecpPublicKey,
/// Measure sends
OnSend,
/// Emit events, driven by the selected mode. See EventCalibrationMode for more info.
/// Emit events
OnEvent,
/// Read/write blocks with different numbers of CBOR fields & links.
OnScanIpldLinks,
Expand Down Expand Up @@ -64,18 +64,11 @@ pub struct OnRecoverSecpPublicKeyParams {
pub seed: u64,
}

#[derive(Serialize, Deserialize)]
pub enum EventCalibrationMode {
/// Produce events with the specified shape.
Shape((usize, usize, usize)),
/// Attempt to reach a target size for the CBOR event.
TargetSize(usize),
}

#[derive(Serialize, Deserialize)]
pub struct OnEventParams {
pub iterations: usize,
pub mode: EventCalibrationMode,
// Total size of the values.
pub total_value_size: usize,
/// Number of entries in the event.
pub entries: usize,
/// Flags to apply to all entries.
Expand Down
3 changes: 2 additions & 1 deletion testing/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ serde_json = "1.0"
bls-signatures = { version = "0.13", default-features = false }
wat = "1.0.66"
hex = "0.4.3"
minstant = "0.1.3"

[features]
default = []
m2-native = []
calibration = []
calibration = ["fvm/gas_calibration"]
Loading

0 comments on commit 0978a29

Please sign in to comment.