Recording time for a Custom defined structure

Let's say we wish to record the time for a given rust code segment of the project

let timer = Instant::now(); 
let response = MyStruct::init(); 
let duration_recorded = timer.elapsed();
return response;

whereas if we create a way for recording the time when it is dropped with the help of std::ops::Drop
something similar or exact like this

pub struct MyStruct(Instant); 

impl std::ops::Drop for MyStruct { 
  fn drop(&mut self) { 
     let duration_recorded = self.0.elapsed(); 
     ... 
  }
}

what do you guys which one is more suitable under what scenarios? does the second one makes it easy for being accurate ?

1 Like

Just my opinion, but I would only use Drop for releasing resources. Note that Drop has special rules around panics.

1 Like

You'd run the risk of dropping long after the intended point IMO. Maybe what you want is a helper function.

fn time<F: FnOnce()>(work: F) -> Duration {
    let timer = Instant::now();
    work();
    timer.elapsed()
}
3 Likes

I suspect would it not add to the cost for calling it too many if assuming this procedure is invoked several times in a row additionally what do you think inline would do to it?

Can we do similar using macro ?

Good point regarding Long dropping that from my understanding maybe we should not be at the mercy of compiler for assuming that it will responsibly drop this the moment we intent it to be!

Also do you think if we manually called drop method on the type would it be a problem ? Incase we were esoteric and had some raw pointers present within it !

You can add #[inline] to the function as an additional hint. You can do it with a macro.

macro_rules! time {
    ($($code:tt)*) => {{
        let timer = ::std::time::Instant::now();
        let _ = { $($code)* };
        timer.elapsed()
    }}
}

// ...
let response;
let duration = time!{
    response = MyStruct::init(); 
};

But honestly, if you care that much, the rough measurements you're going to get with this approach already aren't good enough, and you really want to look into going through the trouble of using something like criterion.

If you don't care enough to do that, you shouldn't care about a missed function call inline or whatever here or there.[1] Other things like context switching or CPU warmup or FS cache, etc etc, will add as much noise or more.

Things drop at well defined points (albeit not necessarily intuitive points). But they also do so automatically and invisibly, so it's easy to forget to manually drop something when you want it to drop before the well defined point.

You can't call Drop::drop directly. You can invoke the destructor[2] by (unsafely) using drop_in_place. But probably you don't want or need to do that, and should instead just (safely) call std::mem::drop.[3]

Most meaningful things you can do with raw pointers also requires unsafe. Anytime you use unsafe, it's on you to understand and uphold the invariants.


  1. Which the Drop approach could also incur, incidentally ↩︎

  2. which will include a call to Drop::drop if it exists, but having a destructor is more general than having a Drop implementation ↩︎

  3. Which simply moves the value to a function where it's automatically dropped -- as the documentation says, there is zero magic going on, and you can write the function yourself ↩︎

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.