diff mbox series

[ovs-dev,v2,2/2] Minimize the number of time calls in time_poll()

Message ID 20210712171529.11161-2-anton.ivanov@cambridgegreys.com
State Changes Requested
Headers show
Series [ovs-dev,v2,1/2] Optimize the poll loop for poll_immediate_wake() | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot success github build: passed

Commit Message

Anton Ivanov July 12, 2021, 5:15 p.m. UTC
From: Anton Ivanov <anton.ivanov@cambridgegreys.com>

time_poll() makes an excessive number of time_msec() calls
which incur a performance penalty.

1. Avoid time_msec() call for timeout calculation when time_poll()
is asked to skip poll()

2. Reuse the time_msec() result from deadline calculation for
last_wakeup and timeout calculation.

Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
---
 lib/timeval.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

Comments

Mark Michelson July 15, 2021, 7:49 p.m. UTC | #1
Hi Anton,

Out of curiosity, has this change made a noticeable impact on performance?

On 7/12/21 1:15 PM, anton.ivanov@cambridgegreys.com wrote:
> From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
> 
> time_poll() makes an excessive number of time_msec() calls
> which incur a performance penalty.
> 
> 1. Avoid time_msec() call for timeout calculation when time_poll()
> is asked to skip poll()
> 
> 2. Reuse the time_msec() result from deadline calculation for
> last_wakeup and timeout calculation.
> 
> Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
> ---
>   lib/timeval.c | 36 +++++++++++++++++++++---------------
>   1 file changed, 21 insertions(+), 15 deletions(-)
> 
> diff --git a/lib/timeval.c b/lib/timeval.c
> index c6ac87376..64ab22e05 100644
> --- a/lib/timeval.c
> +++ b/lib/timeval.c
> @@ -287,7 +287,7 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
>             long long int timeout_when, int *elapsed)
>   {
>       long long int *last_wakeup = last_wakeup_get();
> -    long long int start;
> +    long long int start, now;
>       bool quiescent;
>       int retval = 0;
>   
> @@ -297,28 +297,31 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
>       if (*last_wakeup && !thread_is_pmd()) {
>           log_poll_interval(*last_wakeup);
>       }
> -    start = time_msec();
> +    now = start = time_msec();
>   
>       timeout_when = MIN(timeout_when, deadline);
>       quiescent = ovsrcu_is_quiescent();
>   
>       for (;;) {
> -        long long int now = time_msec();
>           int time_left;
>   
> -        if (now >= timeout_when) {
> +        if (n_pollfds == 0) {
>               time_left = 0;
> -        } else if ((unsigned long long int) timeout_when - now > INT_MAX) {
> -            time_left = INT_MAX;
>           } else {
> -            time_left = timeout_when - now;
> -        }
> -
> -        if (!quiescent) {
> -            if (!time_left) {
> -                ovsrcu_quiesce();
> +            if (now >= timeout_when) {
> +                time_left = 0;
> +            } else if ((unsigned long long int) timeout_when - now > INT_MAX) {
> +                time_left = INT_MAX;
>               } else {
> -                ovsrcu_quiesce_start();
> +                time_left = timeout_when - now;
> +            }
> +
> +            if (!quiescent) {
> +                if (!time_left) {
> +                    ovsrcu_quiesce();
> +                } else {
> +                    ovsrcu_quiesce_start();
> +                }
>               }
>           }
>   
> @@ -329,6 +332,8 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
>            */
>           if (n_pollfds != 0) {
>               retval = poll(pollfds, n_pollfds, time_left);
> +        } else {
> +            retval = 0;
>           }
>           if (retval < 0) {
>               retval = -errno;
> @@ -355,7 +360,8 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
>               ovsrcu_quiesce_end();
>           }
>   
> -        if (deadline <= time_msec()) {
> +        now = time_msec();
> +        if (deadline <= now) {
>   #ifndef _WIN32
>               fatal_signal_handler(SIGALRM);
>   #else
> @@ -372,7 +378,7 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
>               break;
>           }
>       }
> -    *last_wakeup = time_msec();
> +    *last_wakeup = now;
>       refresh_rusage();
>       *elapsed = *last_wakeup - start;
>       return retval;
>
Anton Ivanov July 15, 2021, 8:39 p.m. UTC | #2
On 15/07/2021 20:49, Mark Michelson wrote:
> Hi Anton,
>
> Out of curiosity, has this change made a noticeable impact on 
> performance?

I can't pick it up on OVN heater.

That is not unexpected. It is "noise" compared to the compute time and 
the number of syscalls used in one iteration in northd or ovsdb.

I suspect it will be more useful in places like the vswitch itself where 
the loops are tighter, processing per loop is less and lower latency is 
the key. There, one syscall less per iteration may show up as a 
noticeable difference.

I do not have a benchmark set up for those.

A.

> On 7/12/21 1:15 PM, anton.ivanov@cambridgegreys.com wrote:
>> From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
>>
>> time_poll() makes an excessive number of time_msec() calls
>> which incur a performance penalty.
>>
>> 1. Avoid time_msec() call for timeout calculation when time_poll()
>> is asked to skip poll()
>>
>> 2. Reuse the time_msec() result from deadline calculation for
>> last_wakeup and timeout calculation.
>>
>> Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
>> ---
>>   lib/timeval.c | 36 +++++++++++++++++++++---------------
>>   1 file changed, 21 insertions(+), 15 deletions(-)
>>
>> diff --git a/lib/timeval.c b/lib/timeval.c
>> index c6ac87376..64ab22e05 100644
>> --- a/lib/timeval.c
>> +++ b/lib/timeval.c
>> @@ -287,7 +287,7 @@ time_poll(struct pollfd *pollfds, int n_pollfds, 
>> HANDLE *handles OVS_UNUSED,
>>             long long int timeout_when, int *elapsed)
>>   {
>>       long long int *last_wakeup = last_wakeup_get();
>> -    long long int start;
>> +    long long int start, now;
>>       bool quiescent;
>>       int retval = 0;
>>   @@ -297,28 +297,31 @@ time_poll(struct pollfd *pollfds, int 
>> n_pollfds, HANDLE *handles OVS_UNUSED,
>>       if (*last_wakeup && !thread_is_pmd()) {
>>           log_poll_interval(*last_wakeup);
>>       }
>> -    start = time_msec();
>> +    now = start = time_msec();
>>         timeout_when = MIN(timeout_when, deadline);
>>       quiescent = ovsrcu_is_quiescent();
>>         for (;;) {
>> -        long long int now = time_msec();
>>           int time_left;
>>   -        if (now >= timeout_when) {
>> +        if (n_pollfds == 0) {
>>               time_left = 0;
>> -        } else if ((unsigned long long int) timeout_when - now > 
>> INT_MAX) {
>> -            time_left = INT_MAX;
>>           } else {
>> -            time_left = timeout_when - now;
>> -        }
>> -
>> -        if (!quiescent) {
>> -            if (!time_left) {
>> -                ovsrcu_quiesce();
>> +            if (now >= timeout_when) {
>> +                time_left = 0;
>> +            } else if ((unsigned long long int) timeout_when - now > 
>> INT_MAX) {
>> +                time_left = INT_MAX;
>>               } else {
>> -                ovsrcu_quiesce_start();
>> +                time_left = timeout_when - now;
>> +            }
>> +
>> +            if (!quiescent) {
>> +                if (!time_left) {
>> +                    ovsrcu_quiesce();
>> +                } else {
>> +                    ovsrcu_quiesce_start();
>> +                }
>>               }
>>           }
>>   @@ -329,6 +332,8 @@ time_poll(struct pollfd *pollfds, int 
>> n_pollfds, HANDLE *handles OVS_UNUSED,
>>            */
>>           if (n_pollfds != 0) {
>>               retval = poll(pollfds, n_pollfds, time_left);
>> +        } else {
>> +            retval = 0;
>>           }
>>           if (retval < 0) {
>>               retval = -errno;
>> @@ -355,7 +360,8 @@ time_poll(struct pollfd *pollfds, int n_pollfds, 
>> HANDLE *handles OVS_UNUSED,
>>               ovsrcu_quiesce_end();
>>           }
>>   -        if (deadline <= time_msec()) {
>> +        now = time_msec();
>> +        if (deadline <= now) {
>>   #ifndef _WIN32
>>               fatal_signal_handler(SIGALRM);
>>   #else
>> @@ -372,7 +378,7 @@ time_poll(struct pollfd *pollfds, int n_pollfds, 
>> HANDLE *handles OVS_UNUSED,
>>               break;
>>           }
>>       }
>> -    *last_wakeup = time_msec();
>> +    *last_wakeup = now;
>>       refresh_rusage();
>>       *elapsed = *last_wakeup - start;
>>       return retval;
>>
>
>
Ben Pfaff July 15, 2021, 9:26 p.m. UTC | #3
On Mon, Jul 12, 2021 at 06:15:29PM +0100, anton.ivanov@cambridgegreys.com wrote:
> From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
> 
> time_poll() makes an excessive number of time_msec() calls
> which incur a performance penalty.
> 
> 1. Avoid time_msec() call for timeout calculation when time_poll()
> is asked to skip poll()
> 
> 2. Reuse the time_msec() result from deadline calculation for
> last_wakeup and timeout calculation.
> 
> Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>

I'd like another look at that after patch 1 is revised.
diff mbox series

Patch

diff --git a/lib/timeval.c b/lib/timeval.c
index c6ac87376..64ab22e05 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -287,7 +287,7 @@  time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
           long long int timeout_when, int *elapsed)
 {
     long long int *last_wakeup = last_wakeup_get();
-    long long int start;
+    long long int start, now;
     bool quiescent;
     int retval = 0;
 
@@ -297,28 +297,31 @@  time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
     if (*last_wakeup && !thread_is_pmd()) {
         log_poll_interval(*last_wakeup);
     }
-    start = time_msec();
+    now = start = time_msec();
 
     timeout_when = MIN(timeout_when, deadline);
     quiescent = ovsrcu_is_quiescent();
 
     for (;;) {
-        long long int now = time_msec();
         int time_left;
 
-        if (now >= timeout_when) {
+        if (n_pollfds == 0) {
             time_left = 0;
-        } else if ((unsigned long long int) timeout_when - now > INT_MAX) {
-            time_left = INT_MAX;
         } else {
-            time_left = timeout_when - now;
-        }
-
-        if (!quiescent) {
-            if (!time_left) {
-                ovsrcu_quiesce();
+            if (now >= timeout_when) {
+                time_left = 0;
+            } else if ((unsigned long long int) timeout_when - now > INT_MAX) {
+                time_left = INT_MAX;
             } else {
-                ovsrcu_quiesce_start();
+                time_left = timeout_when - now;
+            }
+
+            if (!quiescent) {
+                if (!time_left) {
+                    ovsrcu_quiesce();
+                } else {
+                    ovsrcu_quiesce_start();
+                }
             }
         }
 
@@ -329,6 +332,8 @@  time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
          */
         if (n_pollfds != 0) {
             retval = poll(pollfds, n_pollfds, time_left);
+        } else {
+            retval = 0;
         }
         if (retval < 0) {
             retval = -errno;
@@ -355,7 +360,8 @@  time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
             ovsrcu_quiesce_end();
         }
 
-        if (deadline <= time_msec()) {
+        now = time_msec();
+        if (deadline <= now) {
 #ifndef _WIN32
             fatal_signal_handler(SIGALRM);
 #else
@@ -372,7 +378,7 @@  time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
             break;
         }
     }
-    *last_wakeup = time_msec();
+    *last_wakeup = now;
     refresh_rusage();
     *elapsed = *last_wakeup - start;
     return retval;