diff mbox

[2/2] time: fix invalid casting on a 32-bit host

Message ID 1462366907-28457-2-git-send-email-matias.elo@nokia.com
State Accepted
Commit 08fe6f0ea4c57cf9721dca8f40b15f5c94db4a93
Headers show

Commit Message

Elo, Matias (Nokia - FI/Espoo) May 4, 2016, 1:01 p.m. UTC
The size of 'struct timespec' may vary on different host
architectures as it includes type long members. This breaks
time functions on a 32-bit x86 host. Fix this by
individually copying struct timespec members to odp_time_t.

Signed-off-by: Matias Elo <matias.elo@nokia.com>
---
 platform/linux-generic/odp_time.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

Comments

Ivan Khoronzhuk May 16, 2016, 2:27 p.m. UTC | #1
Hi Matias,

The odp_time_local and others functions are time sensitive functions,
that's why it was decided to avoid copping as more as possible.

The timespec is not simple "long type". Its type is arch dependent but is always 64bit.
In case of 32 bit system it's defined as long long.
The same for odp_time_t struct. So, at least for now it seems to be the same for
both 32 and 64 bit systems. And I think Bill Fischofer knew about this while adding this
,at first glance, strange union, right Bill?
Yes, it's not the best decision from style point of view, but it's fast and in case of an error
is supposed to be caught by time validation tests.

On 04.05.16 16:01, Matias Elo wrote:
> The size of 'struct timespec' may vary on different host
> architectures as it includes type long members. This breaks
> time functions on a 32-bit x86 host. Fix this by
> individually copying struct timespec members to odp_time_t.
>
> Signed-off-by: Matias Elo <matias.elo@nokia.com>
> ---
>   platform/linux-generic/odp_time.c | 26 +++++++++++++++-----------
>   1 file changed, 15 insertions(+), 11 deletions(-)
>
> diff --git a/platform/linux-generic/odp_time.c b/platform/linux-generic/odp_time.c
> index 040f754..81e0522 100644
> --- a/platform/linux-generic/odp_time.c
> +++ b/platform/linux-generic/odp_time.c
> @@ -11,11 +11,6 @@
>   #include <odp/api/hints.h>
>   #include <odp_debug_internal.h>
>
> -typedef union {
> -	odp_time_t      ex;
> -	struct timespec in;
> -} _odp_time_t;
> -
>   static odp_time_t start_time;
>
>   static inline
> @@ -47,13 +42,17 @@ static inline odp_time_t time_diff(odp_time_t t2, odp_time_t t1)
>   static inline odp_time_t time_local(void)
>   {
>   	int ret;
> -	_odp_time_t time;
> +	odp_time_t time;
> +	struct timespec sys_time;
>
> -	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
> +	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &sys_time);
>   	if (odp_unlikely(ret != 0))
>   		ODP_ABORT("clock_gettime failed\n");
>
> -	return time_diff(time.ex, start_time);
> +	time.tv_sec = sys_time.tv_sec;
> +	time.tv_nsec = sys_time.tv_nsec;
> +
> +	return time_diff(time, start_time);
>   }
>
>   static inline int time_cmp(odp_time_t t2, odp_time_t t1)
> @@ -195,10 +194,15 @@ uint64_t odp_time_to_u64(odp_time_t time)
>   int odp_time_init_global(void)
>   {
>   	int ret;
> -	_odp_time_t time;
> +	struct timespec time;
>
> -	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
> -	start_time = ret ? ODP_TIME_NULL : time.ex;
> +	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time);
> +	if (ret) {
> +		start_time = ODP_TIME_NULL;
> +	} else {
> +		start_time.tv_sec = time.tv_sec;
> +		start_time.tv_nsec = time.tv_nsec;
> +	}
>
>   	return ret;
>   }
>
Bill Fischofer May 16, 2016, 9:41 p.m. UTC | #2
On Mon, May 16, 2016 at 9:27 AM, Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org
> wrote:

> Hi Matias,
>
> The odp_time_local and others functions are time sensitive functions,
> that's why it was decided to avoid copping as more as possible.
>
> The timespec is not simple "long type". Its type is arch dependent but is
> always 64bit.
> In case of 32 bit system it's defined as long long.
> The same for odp_time_t struct. So, at least for now it seems to be the
> same for
> both 32 and 64 bit systems. And I think Bill Fischofer knew about this
> while adding this
> ,at first glance, strange union, right Bill?
>

Yes. The original purpose of that union was not efficiency (though that's a
happy side-effect) but rather to remove the need for ODP applications to be
dependent on the variable expansion of the Linux timespec struct, which is
dependent on POSIX level. That was an earlier bug that caused much grief.


> Yes, it's not the best decision from style point of view, but it's fast
> and in case of an error
> is supposed to be caught by time validation tests.
>
>
> On 04.05.16 16:01, Matias Elo wrote:
>
>> The size of 'struct timespec' may vary on different host
>> architectures as it includes type long members. This breaks
>> time functions on a 32-bit x86 host. Fix this by
>> individually copying struct timespec members to odp_time_t.
>>
>> Signed-off-by: Matias Elo <matias.elo@nokia.com>
>> ---
>>   platform/linux-generic/odp_time.c | 26 +++++++++++++++-----------
>>   1 file changed, 15 insertions(+), 11 deletions(-)
>>
>> diff --git a/platform/linux-generic/odp_time.c
>> b/platform/linux-generic/odp_time.c
>> index 040f754..81e0522 100644
>> --- a/platform/linux-generic/odp_time.c
>> +++ b/platform/linux-generic/odp_time.c
>> @@ -11,11 +11,6 @@
>>   #include <odp/api/hints.h>
>>   #include <odp_debug_internal.h>
>>
>> -typedef union {
>> -       odp_time_t      ex;
>> -       struct timespec in;
>> -} _odp_time_t;
>> -
>>   static odp_time_t start_time;
>>
>>   static inline
>> @@ -47,13 +42,17 @@ static inline odp_time_t time_diff(odp_time_t t2,
>> odp_time_t t1)
>>   static inline odp_time_t time_local(void)
>>   {
>>         int ret;
>> -       _odp_time_t time;
>> +       odp_time_t time;
>> +       struct timespec sys_time;
>>
>> -       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
>> +       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &sys_time);
>>         if (odp_unlikely(ret != 0))
>>                 ODP_ABORT("clock_gettime failed\n");
>>
>> -       return time_diff(time.ex, start_time);
>> +       time.tv_sec = sys_time.tv_sec;
>> +       time.tv_nsec = sys_time.tv_nsec;
>> +
>> +       return time_diff(time, start_time);
>>   }
>>
>>   static inline int time_cmp(odp_time_t t2, odp_time_t t1)
>> @@ -195,10 +194,15 @@ uint64_t odp_time_to_u64(odp_time_t time)
>>   int odp_time_init_global(void)
>>   {
>>         int ret;
>> -       _odp_time_t time;
>> +       struct timespec time;
>>
>> -       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
>> -       start_time = ret ? ODP_TIME_NULL : time.ex;
>> +       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time);
>> +       if (ret) {
>> +               start_time = ODP_TIME_NULL;
>> +       } else {
>> +               start_time.tv_sec = time.tv_sec;
>> +               start_time.tv_nsec = time.tv_nsec;
>> +       }
>>
>>         return ret;
>>   }
>>
>>
> --
> Regards,
> Ivan Khoronzhuk
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp
>
Elo, Matias (Nokia - FI/Espoo) May 17, 2016, 10:23 a.m. UTC | #3
> Hi Matias,

> 

> The odp_time_local and others functions are time sensitive functions,

> that's why it was decided to avoid copping as more as possible.

> 

> The timespec is not simple "long type". Its type is arch dependent but is always

> 64bit.

> In case of 32 bit system it's defined as long long.

> The same for odp_time_t struct. So, at least for now it seems to be the same for

> both 32 and 64 bit systems.


Hi Ivan,

At least for 32/64-bit Ubuntu this is not the case. On a 32-bit system (Ubuntu 16.04) the size of struct timespec is 8 bytes (type is long int) and on a 64-bit system it is 16 bytes. The validation tests were failing before this patch on a 32-bit system.

When it comes to the performance, I wouldn't believe this patch having much of an impact. It's an inline function and the compiler should be able to  optimize out the added copy operations.

-Matias

And I think Bill Fischofer knew about this while adding
> this

> ,at first glance, strange union, right Bill?

> Yes, it's not the best decision from style point of view, but it's fast and in case of

> an error

> is supposed to be caught by time validation tests.

>
Ivan Khoronzhuk May 17, 2016, 11:18 a.m. UTC | #4
On 17.05.16 13:23, Elo, Matias (Nokia - FI/Espoo) wrote:
>> Hi Matias,
>>
>> The odp_time_local and others functions are time sensitive functions,
>> that's why it was decided to avoid copping as more as possible.
>>
>> The timespec is not simple "long type". Its type is arch dependent but is always
>> 64bit.
>> In case of 32 bit system it's defined as long long.
>> The same for odp_time_t struct. So, at least for now it seems to be the same for
>> both 32 and 64 bit systems.
>
> Hi Ivan,
>
> At least for 32/64-bit Ubuntu this is not the case. On a 32-bit system (Ubuntu 16.04) the size of struct timespec is 8 bytes (type is long int) and on a 64-bit system it is 16 bytes. The validation tests were failing before this patch on a 32-bit system.
It's nice to see it captured by val tests, that was expected.

>
> When it comes to the performance, I wouldn't believe this patch having much of an impact. It's an inline function and the compiler should be able to  optimize out the added copy operations.
That's not always true. At least in case of "32/64" issue in question and when optimization is disabled.
The types are different, then better to make odp_time_t to be same size of timespec.

Initially, it was smth like typedef timespec odp_time_t, but new versions of Ubuntu
have some problem with leaking some library internals to ODP project with such definition
(not sure what it was, I'm using 14.04).
Maybe better to align the size of odp_time_t struct with timespec ...?

>
> -Matias
>
> And I think Bill Fischofer knew about this while adding
>> this
>> ,at first glance, strange union, right Bill?
>> Yes, it's not the best decision from style point of view, but it's fast and in case of
>> an error
>> is supposed to be caught by time validation tests.
>>
>
Elo, Matias (Nokia - FI/Espoo) May 17, 2016, 12:17 p.m. UTC | #5
> The types are different, then better to make odp_time_t to be same size of

> timespec.

> 

> Initially, it was smth like typedef timespec odp_time_t, but new versions of

> Ubuntu

> have some problem with leaking some library internals to ODP project with such

> definition

> (not sure what it was, I'm using 14.04).

> Maybe better to align the size of odp_time_t struct with timespec ...?


If someone implements this reliably, preferably with no ifdefs and there's a considerable performance gain it's fine by me. However, there are probably much more "cost effective" optimization targets available.

-Matias
diff mbox

Patch

diff --git a/platform/linux-generic/odp_time.c b/platform/linux-generic/odp_time.c
index 040f754..81e0522 100644
--- a/platform/linux-generic/odp_time.c
+++ b/platform/linux-generic/odp_time.c
@@ -11,11 +11,6 @@ 
 #include <odp/api/hints.h>
 #include <odp_debug_internal.h>
 
-typedef union {
-	odp_time_t      ex;
-	struct timespec in;
-} _odp_time_t;
-
 static odp_time_t start_time;
 
 static inline
@@ -47,13 +42,17 @@  static inline odp_time_t time_diff(odp_time_t t2, odp_time_t t1)
 static inline odp_time_t time_local(void)
 {
 	int ret;
-	_odp_time_t time;
+	odp_time_t time;
+	struct timespec sys_time;
 
-	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
+	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &sys_time);
 	if (odp_unlikely(ret != 0))
 		ODP_ABORT("clock_gettime failed\n");
 
-	return time_diff(time.ex, start_time);
+	time.tv_sec = sys_time.tv_sec;
+	time.tv_nsec = sys_time.tv_nsec;
+
+	return time_diff(time, start_time);
 }
 
 static inline int time_cmp(odp_time_t t2, odp_time_t t1)
@@ -195,10 +194,15 @@  uint64_t odp_time_to_u64(odp_time_t time)
 int odp_time_init_global(void)
 {
 	int ret;
-	_odp_time_t time;
+	struct timespec time;
 
-	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time.in);
-	start_time = ret ? ODP_TIME_NULL : time.ex;
+	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+	if (ret) {
+		start_time = ODP_TIME_NULL;
+	} else {
+		start_time.tv_sec = time.tv_sec;
+		start_time.tv_nsec = time.tv_nsec;
+	}
 
 	return ret;
 }