Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-17 Thread Lei Ni
Thanks everyone for looking into this. I've raised an issue

https://github.com/golang/go/issues/27707 


On Monday, September 17, 2018 at 4:29:15 PM UTC+8, Dave Cheney wrote:
>
> I've confirmed this uses 14% on a random OS X machine. Please raise a bug, 
> https://golang.org/issue/new
>
> On Monday, 17 September 2018 14:29:44 UTC+10, Robert Engels wrote:
>>
>> For reference, similar code under Java consumes 2.5 % CPU.
>>
>> I tested the Go code under OSX, and it is roughly 10%, which seems to be 
>> very high. Might be because the “context switching” is performed/attributed 
>> to the process (since it is internal), where for other systems it is the 
>> system call only, and so most of the cost is attributed to system/kernel 
>> activity.
>>
>>
>>
>> On Sep 16, 2018, at 8:47 AM, Lei Ni  wrote:
>>
>> import (
>>   "time"
>> )
>>
>> func main() {
>>   ticker := time.NewTicker(time.Millisecond)
>>   defer ticker.Stop()
>>   for range ticker.C {
>>   }
>> }
>>
>>
>>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-17 Thread Dave Cheney
I've confirmed this uses 14% on a random OS X machine. Please raise a bug, 
https://golang.org/issue/new

On Monday, 17 September 2018 14:29:44 UTC+10, Robert Engels wrote:
>
> For reference, similar code under Java consumes 2.5 % CPU.
>
> I tested the Go code under OSX, and it is roughly 10%, which seems to be 
> very high. Might be because the “context switching” is performed/attributed 
> to the process (since it is internal), where for other systems it is the 
> system call only, and so most of the cost is attributed to system/kernel 
> activity.
>
>
>
> On Sep 16, 2018, at 8:47 AM, Lei Ni > 
> wrote:
>
> import (
>   "time"
> )
>
> func main() {
>   ticker := time.NewTicker(time.Millisecond)
>   defer ticker.Stop()
>   for range ticker.C {
>   }
> }
>
>
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-16 Thread robert engels
For reference, similar code under Java consumes 2.5 % CPU.

I tested the Go code under OSX, and it is roughly 10%, which seems to be very 
high. Might be because the “context switching” is performed/attributed to the 
process (since it is internal), where for other systems it is the system call 
only, and so most of the cost is attributed to system/kernel activity.



> On Sep 16, 2018, at 8:47 AM, Lei Ni  wrote:
> 
> import (
>   "time"
> )
> 
> func main() {
>   ticker := time.NewTicker(time.Millisecond)
>   defer ticker.Stop()
>   for range ticker.C {
>   }
> }
> 

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-16 Thread Lei Ni
Thanks for the input Jan! 

When running the following exact code, I saw 20% %CPU in top as well, 
measured on a single socket E5-2696v4 server without any vm/container/CPU 
intensive task.  

package main

import (
  "time"
)

func main() {
  ticker := time.NewTicker(time.Millisecond)
  defer ticker.Stop()
  for range ticker.C {
  }
}

The following C++ program is the one I mentioned, I saw ~1% %CPU in top - 

#include 
#include 

int main(int argc, char **argv, char **env)
{
  while(true)
  {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }
}

> If you're observing 10% CPU usage, it means the scheduler does its job in 
about 100 microseconds. Maybe it can be improved but it does not look like 
suspiciously too much to me - considering what's happening behind the 
scenes.

I saw 20% %CPU usage in top when using time.Ticker, and > 10% when using 
time.Sleep(). This causes two real issues - 

1. users of my system keep asking me why an idle server process is still 
taking 20% %CPU every time when they look at top.
2. the system can't scale well when running in its simulation mode. In such 
simulation mode, I'd be running many instances of the same program on a 
multi-core machine each with a slightly different set of inputs (including 
many SIGKILL) for testing purposes. If each process is spending 20% %CPU by 
just having a ticker loop, it ends up wasting a significant portion of 
total CPU resources which could have been spent on more process instances 
for more tests.

Also interesting to know the standard of your mentioned "suspiciously too 
much" - how much is too much? To me, it is an obvious performance issue in 
Go's runtime. To further illustrate the problem, I've come up with another 
program showing that if I move the ticker/sleep part to C and let the C 
code to call my periodic task in Go every 1 millisecond, the %CPU is 
dramatically reduced to 2-3%. I believe this is not the kind of cgo 
"optimization" users should be doing on their own. 



ticker.h
--

#ifndef TEST_TICKER_H
#define TEST_TICKER_H

void cticker();

#endif // TEST_TICKER_H


ticker.c
--

#include 
#include "ticker.h"
#include "_cgo_export.h"

void cticker()
{
  for(int i = 0; i < 3; i++)
  {
usleep(1000);
Gotask();
  }
}


ticker.go
---

package main

/*
#include "ticker.h"
*/
import "C"
import (
  "log"
)

var (
  counter uint64 = 0
)

//export Gotask
func Gotask() {
  counter++
}

func main() {
  C.cticker()
  log.Printf("Gotask called %d times", counter)
}


  

On Sunday, September 16, 2018 at 5:10:07 PM UTC+8, Jan Mercl wrote:
>
> On Sun, Sep 16, 2018 at 10:49 AM Lei Ni > 
> wrote:
> func main() {
> ...
> for {
> select {
> case <-ticker.C:
> // call my function here
> }
> }
> }
>
> Is the above the actual code you're using for the CPU usage "benchmark"? 
> If so, make the loop
>
> for range <-ticker.C  {
> // call my function here
> }
>
> instead.
>
> > As comparison, the same can be done in C++ with about 1% %CPU in top. 
>
> Please show the C++ code to let others know what is meant by "the same", 
> thanks. My guess is that the C++ code only yields the thread to the kernel 
> which is indeed cheaper than rescheduling goroutines in a Go program when 
> one of them blocks or sleeps. If you're observing 10% CPU usage, it means 
> the scheduler does its job in about 100 microseconds. Maybe it can be 
> improved but it does not look like suspiciously too much to me - 
> considering what's happening behind the scenes.
>
> FTR, a 1 msec ticker will make something called 1000 times in a second on 
> a common system only when almost idle otherwise. IIRC, for example Linux 
> schedules threads on a 100 msec base by default.
>
> -- 
>
> -j
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-16 Thread Jan Mercl
On Sun, Sep 16, 2018 at 10:49 AM Lei Ni  wrote:
func main() {
...
for {
select {
case <-ticker.C:
// call my function here
}
}
}

Is the above the actual code you're using for the CPU usage "benchmark"? If
so, make the loop

for range <-ticker.C  {
// call my function here
}

instead.

> As comparison, the same can be done in C++ with about 1% %CPU in top.

Please show the C++ code to let others know what is meant by "the same",
thanks. My guess is that the C++ code only yields the thread to the kernel
which is indeed cheaper than rescheduling goroutines in a Go program when
one of them blocks or sleeps. If you're observing 10% CPU usage, it means
the scheduler does its job in about 100 microseconds. Maybe it can be
improved but it does not look like suspiciously too much to me -
considering what's happening behind the scenes.

FTR, a 1 msec ticker will make something called 1000 times in a second on a
common system only when almost idle otherwise. IIRC, for example Linux
schedules threads on a 100 msec base by default.

-- 

-j

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive

2018-09-16 Thread Lei Ni
Hi all,

In my Go program, I need to call a function roughly every millisecond. 
There is no hard real time requirement, so as long as I can call that 
function roughly 1,000 times a second (or let's say every 0.9-1.1 
millisecond) everything is fine. 

I found time.Ticker and time.Sleep are both pretty expensive, probably 
because the scheduler is doing some of its magics in the background. Is 
there any alternative approach that can allow me to achieve the same with 
much less overhead? Many thanks!


The following program is consistently showing 20-25% of %CPU in top. 

package main

import (
  "time"
)

func main() {
  ticker := time.NewTicker(time.Millisecond)
  defer ticker.Stop()
  for {
select {
case <-ticker.C:
// call my function here
}
  }
}

while the following program is showing 10-15% of %CPU in top

package main

import (
  "time"
)

func main() {
  for {
time.Sleep(time.Millisecond)
// call my function here
  }
}

As comparison, the same can be done in C++ with about 1% %CPU in top. 




Cheers,

Lei 

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.