Skip to content

Commit

Permalink
ebpf: reduce use of unsafe
Browse files Browse the repository at this point in the history
Reduce the use of unsafe transmutes by using the `from_ne_bytes()`
methods to convert the values taken from the BPF Histograms.

Addresses #2
  • Loading branch information
brayniac committed Aug 19, 2019
1 parent 2c1c618 commit cc7dc3c
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 116 deletions.
67 changes: 21 additions & 46 deletions src/samplers/ebpf/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

use crate::common::{BILLION, MILLION, PERCENTILES};
use crate::common::{BILLION, MICROSECOND, MILLION, PERCENTILES};
use crate::config::Config;
use crate::samplers::Sampler;
use crate::stats::{record_distribution, register_distribution};
Expand All @@ -15,7 +15,6 @@ use metrics::*;
use time;

use std::collections::HashMap;
use std::mem;

pub struct Block<'a> {
config: &'a Config,
Expand All @@ -30,33 +29,21 @@ impl<'a> Block<'a> {
let mut current = HashMap::new();
let mut data = self.bpf.table(table);

for entry in data.iter() {
let mut key = entry.key;
let value = entry.value;
for mut entry in data.iter() {
let mut key = [0; 4];
key.copy_from_slice(&entry.key);
let key = u32::from_ne_bytes(key);

// key is a u64 index into a BPF_HISTOGRAM
let mut k = [0_u8; 4];
for (index, byte) in k.iter_mut().enumerate() {
*byte = *key.get(index).unwrap_or(&0);
}
let k: u32 = unsafe { mem::transmute(k) };

// convert the key to a latency in nanoseconds
if let Some(latency) = super::key_to_value(k as u64) {
// value is a u64 count of times that block size was seen
let mut v = [0_u8; 8];
for (index, byte) in v.iter_mut().enumerate() {
*byte = *value.get(index).unwrap_or(&0);
}

let count: u64 = unsafe { mem::transmute(v) };
let mut value = [0; 8];
value.copy_from_slice(&entry.value);
let value = u64::from_ne_bytes(value);

// store the size-count pair into the hashmap
current.insert(latency * 1000, count as u32);
if let Some(key) = super::key_to_value(key as u64) {
current.insert(key * MICROSECOND, value as u32);
}

// clear the source counter
let _ = data.set(&mut key, &mut [0_u8; 8]);
let _ = data.set(&mut entry.key, &mut [0_u8; 8]);
}
if !self.initialized {
self.register();
Expand All @@ -72,33 +59,21 @@ impl<'a> Block<'a> {
let mut current = HashMap::new();
let mut data = self.bpf.table(table);

for entry in data.iter() {
let mut key = entry.key;
let value = entry.value;

// key is a u64 index into a BPF_HISTOGRAM
let mut k = [0_u8; 4];
for (index, byte) in k.iter_mut().enumerate() {
*byte = *key.get(index).unwrap_or(&0);
}
let k: u32 = unsafe { mem::transmute(k) };

// convert the key to a block size in kbytes
if let Some(size) = super::key_to_value(k as u64) {
// value is a u64 count of times that block size was seen
let mut v = [0_u8; 8];
for (index, byte) in v.iter_mut().enumerate() {
*byte = *value.get(index).unwrap_or(&0);
}
for mut entry in data.iter() {
let mut key = [0; 4];
key.copy_from_slice(&entry.key);
let key = u32::from_ne_bytes(key);

let count: u64 = unsafe { mem::transmute(v) };
let mut value = [0; 8];
value.copy_from_slice(&entry.value);
let value = u64::from_ne_bytes(value);

// store the size-count pair into the hashmap
current.insert(size, count as u32);
if let Some(key) = super::key_to_value(key as u64) {
current.insert(key, value as u32);
}

// clear the source counter
let _ = data.set(&mut key, &mut [0_u8; 8]);
let _ = data.set(&mut entry.key, &mut [0_u8; 8]);
}
if !self.initialized {
self.register();
Expand Down
33 changes: 10 additions & 23 deletions src/samplers/ebpf/ext4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use metrics::*;
use time;

use std::collections::HashMap;
use std::mem;

pub struct Ext4<'a> {
bpf: BPF,
Expand Down Expand Up @@ -125,33 +124,21 @@ fn map_from_table(table: &mut Table) -> HashMap<u64, u32> {
let mut current = HashMap::new();

trace!("transferring data to userspace");
for entry in table.iter() {
let mut key = entry.key;
let value = entry.value;

// key is a u64 index into a histogram
let mut k = [0_u8; 4];
for (index, byte) in k.iter_mut().enumerate() {
*byte = *key.get(index).unwrap_or(&0);
}
let k: u32 = unsafe { mem::transmute(k) };

// convert the key to a block size in kbytes
if let Some(key) = super::key_to_value(k as u64) {
// value is a u32 count of times that block size was seen
let mut v = [0_u8; 8];
for (index, byte) in v.iter_mut().enumerate() {
*byte = *value.get(index).unwrap_or(&0);
}
for mut entry in table.iter() {
let mut key = [0; 4];
key.copy_from_slice(&entry.key);
let key = u32::from_ne_bytes(key);

let count: u64 = unsafe { mem::transmute(v) };
let mut value = [0; 8];
value.copy_from_slice(&entry.value);
let value = u64::from_ne_bytes(value);

// store the size-count pair into the hashmap
current.insert(key * MICROSECOND, count as u32);
if let Some(key) = super::key_to_value(key as u64) {
current.insert(key * MICROSECOND, value as u32);
}

// clear the source counter
let _ = table.set(&mut key, &mut [0_u8; 8]);
let _ = table.set(&mut entry.key, &mut [0_u8; 8]);
}
current
}
34 changes: 10 additions & 24 deletions src/samplers/ebpf/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use metrics::*;
use time;

use std::collections::HashMap;
use std::mem;

pub struct Scheduler<'a> {
bpf: BPF,
Expand Down Expand Up @@ -65,34 +64,21 @@ impl<'a> Sampler<'a> for Scheduler<'a> {
let mut data = self.bpf.table("dist");

trace!("copying data to userspace");
for entry in data.iter() {
let mut key = entry.key;
let value = entry.value;

// key is a u64 index into a BPF_HISTOGRAM
let mut k = [0_u8; 4];
for (index, byte) in k.iter_mut().enumerate() {
*byte = *key.get(index).unwrap_or(&0);
}
let k: u32 = unsafe { mem::transmute(k) };

// convert the key to a block size in kbytes
if let Some(latency) = super::key_to_value(k as u64) {
let latency = latency * MICROSECOND;
// value is a u64 count of times that block size was seen
let mut v = [0_u8; 8];
for (index, byte) in v.iter_mut().enumerate() {
*byte = *value.get(index).unwrap_or(&0);
}
for mut entry in data.iter() {
let mut key = [0; 4];
key.copy_from_slice(&entry.key);
let key = u32::from_ne_bytes(key);

let count: u64 = unsafe { mem::transmute(v) };
let mut value = [0; 8];
value.copy_from_slice(&entry.value);
let value = u64::from_ne_bytes(value);

// store the size-count pair into the hashmap
current.insert(latency, count as u32);
if let Some(key) = super::key_to_value(key as u64) {
current.insert(key * MICROSECOND, value as u32);
}

// clear the source counter
let _ = data.set(&mut key, &mut [0_u8; 8]);
let _ = data.set(&mut entry.key, &mut [0_u8; 8]);
}
trace!("data copied to userspace");
if !self.initialized {
Expand Down
33 changes: 10 additions & 23 deletions src/samplers/ebpf/xfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use metrics::*;
use time;

use std::collections::HashMap;
use std::mem;

pub struct Xfs<'a> {
bpf: BPF,
Expand Down Expand Up @@ -113,33 +112,21 @@ impl<'a> Sampler<'a> for Xfs<'a> {

fn map_from_table(table: &mut Table) -> HashMap<u64, u32> {
let mut current = HashMap::new();
for entry in table.iter() {
let mut key = entry.key;
let value = entry.value;

// key is a u64 index into a histogram
let mut k = [0_u8; 4];
for (index, byte) in k.iter_mut().enumerate() {
*byte = *key.get(index).unwrap_or(&0);
}
let k: u32 = unsafe { mem::transmute(k) };

// convert the key to a block size in kbytes
if let Some(key) = super::key_to_value(k as u64) {
// value is a u32 count of times that block size was seen
let mut v = [0_u8; 8];
for (index, byte) in v.iter_mut().enumerate() {
*byte = *value.get(index).unwrap_or(&0);
}
for mut entry in table.iter() {
let mut key = [0; 4];
key.copy_from_slice(&entry.key);
let key = u32::from_ne_bytes(key);

let count: u64 = unsafe { mem::transmute(v) };
let mut value = [0; 8];
value.copy_from_slice(&entry.value);
let value = u64::from_ne_bytes(value);

// store the size-count pair into the hashmap
current.insert(key * MICROSECOND, count as u32);
if let Some(key) = super::key_to_value(key as u64) {
current.insert(key * MICROSECOND, value as u32);
}

// clear the source counter
let _ = table.set(&mut key, &mut [0_u8; 8]);
let _ = table.set(&mut entry.key, &mut [0_u8; 8]);
}
current
}

0 comments on commit cc7dc3c

Please sign in to comment.