FAQ
<https://lh3.googleusercontent.com/-C-0xJg-YK-M/VeQvV0-ekMI/AAAAAAAAAjA/HXyGRrFo-7o/s1600/goprof.png>

Hi,

I'm profiling a Go program and I've noticed that "defer" instruction CPU
usage is the 18% of the total CPU program usage. Is this normal?

My code is like this:
     c.mutex.RLock()
     defer c.mutex.RUnlock()
     ...

Thanks,
David

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Ian Lance Taylor at Aug 31, 2015 at 3:22 pm

    On Mon, Aug 31, 2015 at 3:44 AM, wrote:

    I'm profiling a Go program and I've noticed that "defer" instruction CPU
    usage is the 18% of the total CPU program usage. Is this normal?

    My code is like this:
    c.mutex.RLock()
    defer c.mutex.RUnlock()
    ...
    If that's your whole program, then, yes, it is normal....

    The defer statement is fairly fast, but it's true that it is not as fast as
    it could be. There is some discussion of making defer run faster in
    https://golang.org/issue/6980 . I also think it might be possible to speed
    up the fairly common case of a zero-argument defer by skipping the argument
    handling.

    Ian

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Paul Borman at Aug 31, 2015 at 5:22 pm
    I have taken the practice to doing the defer prior to the lock:

    defer mu.Unlock()
    mu.Lock()

    defer does take time, as you noticed, so if you are going to use defer,
    doing it outside of the lock makes the critical section just a smidgen
    shorter. Of course, even more efficient is not do a defer at all and just
    call Unlock after the region (and every place you can exit).

    This re-ordering was suggested by Dmitry Vyukov sometime back.

         -Paul
    On Mon, Aug 31, 2015 at 8:22 AM, Ian Lance Taylor wrote:
    On Mon, Aug 31, 2015 at 3:44 AM, wrote:


    I'm profiling a Go program and I've noticed that "defer" instruction CPU
    usage is the 18% of the total CPU program usage. Is this normal?

    My code is like this:
    c.mutex.RLock()
    defer c.mutex.RUnlock()
    ...
    If that's your whole program, then, yes, it is normal....

    The defer statement is fairly fast, but it's true that it is not as fast
    as it could be. There is some discussion of making defer run faster in
    https://golang.org/issue/6980 . I also think it might be possible to
    speed up the fairly common case of a zero-argument defer by skipping the
    argument handling.

    Ian

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Manxi David at Sep 1, 2015 at 11:34 am
    Changing the order to that, will reduce thread contention, but I don't
    think it will make the defer instruction faster. Am I right?

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Paul Borman at Sep 1, 2015 at 2:41 pm
    Correct, it does not make defer faster, it only reduces lock contention (by
    a small amount). It more acknowledges your point that defer is not free,
    which is why deferring the unlock before the lock makes sense.

         -Paul
    On Tue, Sep 1, 2015 at 4:33 AM, wrote:


    Changing the order to that, will reduce thread contention, but I don't
    think it will make the defer instruction faster. Am I right?

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Sep 2, 2015 at 12:46 am
    That approach could cause a problem. If Lock() fails (not sure how) then
    the deferred Unlock() will panic or worse it may actually Unlock() the
    mutex that another thread may have locked in the mean time introducing an
    ugly bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an optimization
    otherwise it's probably best to live with it and wait for the runtime to
    improve the performance of defer.
    On Monday, August 31, 2015 at 10:22:39 AM UTC-7, Paul Borman wrote:

    I have taken the practice to doing the defer prior to the lock:

    defer mu.Unlock()
    mu.Lock()

    defer does take time, as you noticed, so if you are going to use defer,
    doing it outside of the lock makes the critical section just a smidgen
    shorter. Of course, even more efficient is not do a defer at all and just
    call Unlock after the region (and every place you can exit).

    This re-ordering was suggested by Dmitry Vyukov sometime back.

    -Paul

    On Mon, Aug 31, 2015 at 8:22 AM, Ian Lance Taylor <ia...@golang.org
    <javascript:>> wrote:
    On Mon, Aug 31, 2015 at 3:44 AM, <manxi...@gmail.com <javascript:>>
    wrote:

    I'm profiling a Go program and I've noticed that "defer" instruction CPU
    usage is the 18% of the total CPU program usage. Is this normal?

    My code is like this:
    c.mutex.RLock()
    defer c.mutex.RUnlock()
    ...
    If that's your whole program, then, yes, it is normal....

    The defer statement is fairly fast, but it's true that it is not as fast
    as it could be. There is some discussion of making defer run faster in
    https://golang.org/issue/6980 . I also think it might be possible to
    speed up the fairly common case of a zero-argument defer by skipping the
    argument handling.

    Ian

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Caleb Spare at Sep 2, 2015 at 12:57 am

    That approach could cause a problem. If Lock() fails (not sure how) then the
    deferred Unlock() will panic or worse it may actually Unlock() the mutex
    that another thread may have locked in the mean time introducing an ugly
    bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an optimization
    otherwise it's probably best to live with it and wait for the runtime to
    improve the performance of defer.
    There is no failure mode that ordering the Lock/Unlock in the
    "correct" way would handle but the "incorrect" ordering wouldn't
    handle. Lock doesn't return an error, for instance. So I don't agree
    with this.

    -Caleb

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Sep 2, 2015 at 1:05 am

    On Tuesday, September 1, 2015 at 5:57:42 PM UTC-7, Caleb Spare wrote:
    That approach could cause a problem. If Lock() fails (not sure how) then the
    deferred Unlock() will panic or worse it may actually Unlock() the mutex
    that another thread may have locked in the mean time introducing an ugly
    bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an optimization
    otherwise it's probably best to live with it and wait for the runtime to
    improve the performance of defer.
    There is no failure mode that ordering the Lock/Unlock in the
    "correct" way would handle but the "incorrect" ordering wouldn't
    handle. Lock doesn't return an error, for instance. So I don't agree
    with this.
    There isn't one today but what if in the future Lock() can panic? I don't
    know if that would be acceptable behavior under the 1.x compatibility
    rules, but even if it does in 2.x it will make it hard to catch such bugs,
    the code will compile just fine but the logic will be wrong.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Caleb Spare at Sep 2, 2015 at 1:11 am
    Yes that would be a behavior change that wouldn't be allowed under the
    compatibility rules. Also if Lock could panic, then this code:

    mu.Lock()
    defer mu.Unlock()

    would still crash in that case because it doesn't catch the panic.
    On Tue, Sep 1, 2015 at 6:05 PM, Tim K wrote:

    On Tuesday, September 1, 2015 at 5:57:42 PM UTC-7, Caleb Spare wrote:

    That approach could cause a problem. If Lock() fails (not sure how) then
    the
    deferred Unlock() will panic or worse it may actually Unlock() the mutex
    that another thread may have locked in the mean time introducing an ugly
    bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an optimization
    otherwise it's probably best to live with it and wait for the runtime to
    improve the performance of defer.
    There is no failure mode that ordering the Lock/Unlock in the
    "correct" way would handle but the "incorrect" ordering wouldn't
    handle. Lock doesn't return an error, for instance. So I don't agree
    with this.
    There isn't one today but what if in the future Lock() can panic? I don't
    know if that would be acceptable behavior under the 1.x compatibility rules,
    but even if it does in 2.x it will make it hard to catch such bugs, the code
    will compile just fine but the logic will be wrong.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Sep 2, 2015 at 1:13 am
    Right, but it would not end up unlocking the mutex that may have been
    locked by some other goroutine.
    On Tuesday, September 1, 2015 at 6:11:16 PM UTC-7, Caleb Spare wrote:

    Yes that would be a behavior change that wouldn't be allowed under the
    compatibility rules. Also if Lock could panic, then this code:

    mu.Lock()
    defer mu.Unlock()

    would still crash in that case because it doesn't catch the panic.

    On Tue, Sep 1, 2015 at 6:05 PM, Tim K <tim....@gmail.com <javascript:>>
    wrote:
    On Tuesday, September 1, 2015 at 5:57:42 PM UTC-7, Caleb Spare wrote:

    That approach could cause a problem. If Lock() fails (not sure how)
    then
    the
    deferred Unlock() will panic or worse it may actually Unlock() the
    mutex
    that another thread may have locked in the mean time introducing an
    ugly
    bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an
    optimization
    otherwise it's probably best to live with it and wait for the runtime
    to
    improve the performance of defer.
    There is no failure mode that ordering the Lock/Unlock in the
    "correct" way would handle but the "incorrect" ordering wouldn't
    handle. Lock doesn't return an error, for instance. So I don't agree
    with this.
    There isn't one today but what if in the future Lock() can panic? I don't
    know if that would be acceptable behavior under the 1.x compatibility rules,
    but even if it does in 2.x it will make it hard to catch such bugs, the code
    will compile just fine but the logic will be wrong.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Paul Borman at Sep 2, 2015 at 1:55 am
    If Lock panics then the defer is the least of your concerns.

    Fortunately, lock does not panic, it does not return an error. Lock does
    what it says it does. I have no interest in coding around a hypothetical
    Lock implementation that we don't use.

    You are free to order those two statements how ever you want. For an
    uncontested lock there is no difference in time. For a contested lock then
    doing the defer first will shorten the critical section (not by much, but
    by an amount you can measure). You are free to do them in either order,
    but both are safe (unless your program has already lost memory safety, at
    which point it does not matter) and functionally equivalent.
    On Tue, Sep 1, 2015 at 6:13 PM, Tim K wrote:

    Right, but it would not end up unlocking the mutex that may have been
    locked by some other goroutine.
    On Tuesday, September 1, 2015 at 6:11:16 PM UTC-7, Caleb Spare wrote:

    Yes that would be a behavior change that wouldn't be allowed under the
    compatibility rules. Also if Lock could panic, then this code:

    mu.Lock()
    defer mu.Unlock()

    would still crash in that case because it doesn't catch the panic.
    On Tue, Sep 1, 2015 at 6:05 PM, Tim K wrote:

    On Tuesday, September 1, 2015 at 5:57:42 PM UTC-7, Caleb Spare wrote:

    That approach could cause a problem. If Lock() fails (not sure how)
    then
    the
    deferred Unlock() will panic or worse it may actually Unlock() the
    mutex
    that another thread may have locked in the mean time introducing an
    ugly
    bug. I'm not sure it's safe to do so, unless I'm missing something.

    You should probably have a very strong reason for such an
    optimization
    otherwise it's probably best to live with it and wait for the
    runtime to
    improve the performance of defer.
    There is no failure mode that ordering the Lock/Unlock in the
    "correct" way would handle but the "incorrect" ordering wouldn't
    handle. Lock doesn't return an error, for instance. So I don't agree
    with this.
    There isn't one today but what if in the future Lock() can panic? I don't
    know if that would be acceptable behavior under the 1.x compatibility rules,
    but even if it does in 2.x it will make it hard to catch such bugs, the code
    will compile just fine but the logic will be wrong.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Will Newton at Sep 2, 2015 at 8:04 am

    On 2 September 2015 at 02:55, 'Paul Borman' via golang-nuts wrote:
    If Lock panics then the defer is the least of your concerns.

    Fortunately, lock does not panic, it does not return an error. Lock does
    what it says it does. I have no interest in coding around a hypothetical
    Lock implementation that we don't use.

    You are free to order those two statements how ever you want. For an
    uncontested lock there is no difference in time. For a contested lock then
    doing the defer first will shorten the critical section (not by much, but by
    an amount you can measure). You are free to do them in either order, but
    both are safe (unless your program has already lost memory safety, at which
    point it does not matter) and functionally equivalent.
    One measurable cost of these types of micro-optimization is that it
    looks odd, so programmers who have not seen the idiom before may
    change the statements back to the "right" order unless you add
    comments explaining the idiom to every call site. In any case I would
    expect truly performance critical critical sections to not use defer
    at all.

    My advice would be: do it in the natural order unless it measurably
    improves performance to do otherwise, and then comment it.

    --
    Will Newton
    Software - Cocoon (http://cocoon.life)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Paul Borman at Sep 2, 2015 at 2:32 pm
    Everything looks odd the first time you see it.

    a, b := b, a

    t := t


    Both of those look odd to a programmer unfamiliar with either concept, the
    can probably reason out the first one, the second is a little more
    difficult, but the effort of learning why they work is well worth it.

    As for lok order, if you don't want to put the defer first, then don't. If
    a programmer cannot figure out that

    defer mu.Unlock()
    mu.Lock()


    is functionally equivalent to

    mu.Lock()
    defer mu.Unlock()


    then I don't think the main problem is the order. There is no need to add
    extra comments (just like the first two examples given above). Also, if
    you don't know why someone would use this order, and you stop and think
    about it, hopefully you will come to the conclusion that it shortens the
    critical section, also prompting you to think about your critical sections
    and making sure they are short. Anyhow, use it or don't. My comment was I
    do use it because defers are not free, which supported the OP's point. Ian
    has said defers will become less expensive in the future. Great! I will
    probably continue to use this order, I like what it implies, but you can
    use what order you like. It is one of the great things about freewill ;-)
    On Wed, Sep 2, 2015 at 1:03 AM, Will Newton wrote:

    On 2 September 2015 at 02:55, 'Paul Borman' via golang-nuts
    wrote:
    If Lock panics then the defer is the least of your concerns.

    Fortunately, lock does not panic, it does not return an error. Lock does
    what it says it does. I have no interest in coding around a hypothetical
    Lock implementation that we don't use.

    You are free to order those two statements how ever you want. For an
    uncontested lock there is no difference in time. For a contested lock then
    doing the defer first will shorten the critical section (not by much, but by
    an amount you can measure). You are free to do them in either order, but
    both are safe (unless your program has already lost memory safety, at which
    point it does not matter) and functionally equivalent.
    One measurable cost of these types of micro-optimization is that it
    looks odd, so programmers who have not seen the idiom before may
    change the statements back to the "right" order unless you add
    comments explaining the idiom to every call site. In any case I would
    expect truly performance critical critical sections to not use defer
    at all.

    My advice would be: do it in the natural order unless it measurably
    improves performance to do otherwise, and then comment it.

    --
    Will Newton
    Software - Cocoon (http://cocoon.life)
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedAug 31, '15 at 2:58p
activeSep 2, '15 at 2:32p
posts13
users6
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase