Re: Can we implement ctype functions through table?

2020-07-29 Thread Gregory Nutt


Another negative thing about the table driven C type functions is that 
in the PROTECTED build, there will need to be two ctyle look-up 
tables:  One in user space and one in kernel space.  So the overhead 
will 512, not 256, bytes in that configuration.


Perhaps we would use the macros inside of the OS and the lookup table 
outside of the OS?


   #ifdef __KERNEL__
   #  define isdigit(c)   ((c) >= '0' && (c) <= '9')
   #else
   #  define isdigit(c)   ((table((unsigned)c) & __DIGIT_MASK) != 0)
   #endif

Then perhaps we could avoid the duplicate kernel-space lookup table?




Re: Can we implement ctype functions through table?

2020-07-29 Thread Nathan Hartman
Macros that evaluate their parameters more than once are dangerous for a
variety of reasons.

On Wed, Jul 29, 2020 at 11:32 AM David Sidrane  wrote:
> K&R warns against using macros in loops. Experienced programmers (especially
> embedded) know not to write code like shown in the "reason" for needing this
> change.

True, but at the call site, use of a macro looks just like a function call, so
good macro writing is to make sure it works just like a function call, no
matter where it's used.

Furthermore, over time, the implementation of a macro could change from macro
to function, or from function to macro. Or you might build the application
software on NuttX one day and on a PC OS the next. So if the macro ends up
being used in a loop, it might not be because the programmer is inexperienced,
but because the implementation (or the platform) changed after the code was
written.

Also, you don't know where/how these macros are being used. Perhaps someone is
using a 3rd party library that uses these macros and assumes they are safe.

Because of all these reasons, it is very important, when writing macros, to
make sure they can be used in all possible scenarios without causing problems.

That includes:
* Evaluating parameters once.
* If the macro is multiple statements, as opposed to an expression, wrapping
  those statements in do { ... } while (0).

I think these things are the responsibility of the macro writer, not the macro
caller.

Regarding isalpha() and friends:

On Wed, Jul 29, 2020 at 2:54 AM Xiang Xiao  wrote:
> 2.Change macro to normal function and lose some performance
> 3.Change macro to inline function and some old compilers may generate
> the bloat code

Given all of the above, and the various concerns voiced here, I think option 2
looks best/safest in the context of embedded systems. While some here might
gawk at the performance penalty of a function call, I agree with Greg that:

> Most released, deeply embedded software  does not do a lot of string
> processing.  So I could imagine that a motor control system that only
> has a couple of uses of ctype functions but would pay a pretty big size
> penalty for using a table.

I think function call overhead isn't quite as horrible as its reputation might
suggest. In fact, if you have macros that evaluate their parameters more than
once, you potentially get a much bigger performance penalty. (I just recently
discovered use of min() and max() macros in code I maintain. Those are
implemented as ((a) < (b)) ? (a) : (b). And the parameters passed to these
macros at the call site were the results of function calls, those functions
were making time-consuming calculations, and they were being executed
redundantly because of the macros evaluating their parameters more than once!
That is a much bigger performance penalty!

On Wed, Jul 29, 2020 at 8:42 AM spudaneco  wrote:
> I would consider option 3 to be the worst choice.  That could bloat can be 
> enormous and unacceptable as I have seen in the past.  I saw growth by many 
> kbyte in such cases. Not a good compromise.

I wonder if there exists a good solution for the inline function problem that
will be C89 compliant, avoid the code bloat, and not create a maintenance
nightmare. I don't know what that is yet, but if we find a solution, it will
be helpful for other things besides the isalpha() (and friends) macros.

Nathan


RE: Can we implement ctype functions through table?

2020-07-29 Thread David Sidrane
Is the example code a port from a bigger system?

K&R warns against using macros in loops. Experienced programmers (especially
embedded) know not to write code like shown in the "reason" for needing this
change.

At this point the acid test is sizeof(how many macros) == "256 | 512" (If we
cannot use MPU)

I still feel it should be a CONFIG setting and default it to the table,
describe the pit falls in Knonfig if it is changed to a macros and document
the code bloat in the README.

This will save past users on Nuttx, on constrained system, to have a chance
to fix running out of FLASH space when isalpha() is used one (properly).

Maybe this is not as important to companies with their own chip foundries,
but we still need to be inclusive.

David


-Original Message-
From: Xiang Xiao [mailto:xiaoxiang781...@gmail.com]
Sent: Tuesday, July 28, 2020 11:54 PM
To: dev@nuttx.apache.org
Subject: RE: Can we implement ctype functions through table?

The new option just make the situation worse. The same code works in
some configurations, but breaks in other configurations.
Since the standard confirmation is the most important principle for
NuttX, we have three options:
1.Implement ctype function with table and add 256 byte to ROM
2.Change macro to normal function and lose some performance
3.Change macro to inline function and some old compilers may generate
the bloat code
all ctype functions are one line code, so option 3 may be a good compromise.


> -Original Message-
> From: David Sidrane 
> Sent: Tuesday, July 28, 2020 8:23 PM
> To: dev@nuttx.apache.org
> Subject: RE: Can we implement ctype functions through table?
>
> Xiang,
>
> If there is a small usage do you think flash will grow by 256 bytes? I
> would be surprised.
>
> Should you uses a config option?
>
> David
>
>
> -Original Message-
> From: Xiang Xiao [mailto:xiaoxiang781...@gmail.com]
> Sent: Monday, July 27, 2020 10:40 PM
> To: dev@nuttx.apache.org
> Subject: RE: Can we implement ctype functions through table?
>
> Decorate the table with IPTR and access the element through up_romgetc,
> just like printf series function.
>
> > -Original Message-
> > From: Gregory Nutt 
> > Sent: Tuesday, July 28, 2020 12:44 PM
> > To: dev@nuttx.apache.org
> > Subject: Re: Can we implement ctype functions through table?
> >
> > What about platforms like AVR?  That would not be a good decision for
> > AVR since it is a harvard machine and cannot access data in ROM
> > without special operations.
> >
> >
> > On 7/27/2020 9:55 PM, Xiang Xiao wrote:
> > > Hi all,
> > > For example, here is isspace implementation:
> > > #  define isspace(c) \
> > >  ((c) == ' '  || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
> > >   (c) == '\f' || (c) == '\v')
> > > The argument of c will evaluate 6 times, which make the following
> > > code suddenly fail:
> > > while (end != begin)
> > >{
> > >  If (!isspace(*--end))
> > >{
> > >   break;
> > >}
> > >}
> > > But it work well with other libc implementation, because all other
> > > libc utilize a table to classify  the char type:
> > > https://github.com/bminor/newlib/blob/master/newlib/libc/include/cty
> > > pe
> > > .h#L97
> > > https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197
> > > and the argument only need evaluate once.
> > > So my question is: can we implement ctype functions through table to
> > > improve the compatibility?
> > > Yes, the table need take more 256 bytes ROM space, but the complex
> > > expression used in NuttX also bloat the code size, especially
> > > considering ctype function is used very frequently.
> > >
> > > Thanks
> > > Xiang
> > >


Re: Can we implement ctype functions through table?

2020-07-29 Thread Gregory Nutt
Another negative thing about the table driven C type functions is that 
in the PROTECTED build, there will need to be two ctyle look-up tables:  
One in user space and one in kernel space.  So the overhead will 512, 
not 256, bytes in that configuration.


Also, a minor correction:


The table look-up version would be something like

#  define isdigit(c)  ( (table(c) & __DIGIT_MASK) != 0)

Given c in a register that would boil down to something like:

  * get the address of the table
  * offset by (c)


 * Fetch table entry from FLASH (big performance hit)


  * AND with __DIGIT_MASK
  * compare with zero





Re: Can we implement ctype functions through table?

2020-07-29 Thread Gregory Nutt



And if the macro versions are employed a few times then they would quickly
grow larger than the table anyways.


The table access is not free.  There is overhead in both cases, 
depending primarily on the complexity of the ctype comparison.


For is isdigit() the comparison is currently just:

   #  define isdigit(c)   ((c) >= '0' && (c) <= '9')

Given c in a register that would boil down to something like the following:

 * compare c to '0'
 * branch if c < '0'
 * compare c to '9'
 * branch if c > '9'

The table look-up version would be something like

   #  define isdigit(c)  ( (table(c) & __DIGIT_MASK) != 0)

Given c in a register that would boil down to something like:

 * get the address of the table
 * offset by (c)
 * AND with __DIGIT_MASK
 * compare with zero
 * branch if zero

So there is no dramatic size savings in that particular case. And the 
fetch from FLASH is a performance killer too.  Reducing size is not a 
super strong argument of this change. There would be a substantial 
reduction in size for some larger more complex ctype functions, 
however.  Like isalnum():


   #  define islower(c)   ((c) >= 'a' && (c) <= 'z')
   #  define isupper(c)   ((c) >= 'A' && (c) <= 'Z')
   #  define isalpha(c)   (islower(c) || isupper(c))
   #  define isdigit(c) ((c) >= '0' && (c) <= '9')
   #  define isalnum(c)   (isalpha(c) || isdigit(c))

The only pressing argument for change is the fact that the argument is 
currently re-evaluated numerous times.  That is a problem.


Most released, deeply embedded software  does not do a lot of string 
processing.  So I could imagine that a motor control system that only 
has a couple of uses of ctype functions but would pay a pretty big size 
penalty for using a table.





Re: Can we implement ctype functions through table?

2020-07-29 Thread Lucas Vinicius Hartmann
And if the macro versions are employed a few times then they would quickly
grow larger than the table anyways.
--
Lucas Vinicius Hartmann

Subscription software is ransomware disguised.


Em qua., 29 de jul. de 2020 às 10:41, Gregory Nutt 
escreveu:

>
> > What about platforms like AVR?  That would not be a good decision for
> > AVR since it is a harvard machine and cannot access data in ROM
> > without special operations.
>
> This is not a show stopper, at least not for the AVR.  While a
> table-driven solution is not optimal for AVR, it will support access to
> constant data in ROM if the data has the storage class IOBJ as defined
> in include/nuttx/compiler.h.  I don't know if the compiler will
> automatically generate the correct instruction to access the table
> across the bus bridge; I am not an AVR expert. There is a up_ function
> may need to be used to access the ROM table???
>
> AVR Memory:  https://microchipdeveloper.com/8avr:memory
> C Interface:
>
> http://ww1.microchip.com/downloads/en/AppNotes/Atmel-2575-C-Functions-for-Reading-and-Writing-to-Flash-Memory_ApplicationNote_AVR106.pdf
>
> Hmm.. I notice that compiler.h defines IOBJ as __flash but the above
> document says:  "The datatypes are actually used as __flashor
> __farflashpointers (consequently 16 and 24 bit)."  That should be change
> to __farflash.
>
>


Re: Can we implement ctype functions through table?

2020-07-29 Thread Gregory Nutt

On 7/29/2020 7:41 AM, Gregory Nutt wrote:


What about platforms like AVR?  That would not be a good decision for 
AVR since it is a harvard machine and cannot access data in ROM 
without special operations. 


This is not a show stopper, at least not for the AVR.  While a 
table-driven solution is not optimal for AVR, it will support access 
to constant data in ROM if the data has the storage class IOBJ as 
defined in include/nuttx/compiler.h.  I don't know if the compiler 
will automatically generate the correct instruction to access the 
table across the bus bridge; I am not an AVR expert.  There is a up_ 
function may need to be used to access the ROM table???


AVR Memory: https://microchipdeveloper.com/8avr:memory
C Interface: 
http://ww1.microchip.com/downloads/en/AppNotes/Atmel-2575-C-Functions-for-Reading-and-Writing-to-Flash-Memory_ApplicationNote_AVR106.pdf


Hmm.. I notice that compiler.h defines IOBJ as __flash but the above 
document says:  "The datatypes are actually used as __flashor 
__farflashpointers (consequently 16 and 24 bit)."  That should be 
change to __farflash.


Much clearer information here: 
https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html





Re: Can we implement ctype functions through table?

2020-07-29 Thread Gregory Nutt


What about platforms like AVR?  That would not be a good decision for 
AVR since it is a harvard machine and cannot access data in ROM 
without special operations. 


This is not a show stopper, at least not for the AVR.  While a 
table-driven solution is not optimal for AVR, it will support access to 
constant data in ROM if the data has the storage class IOBJ as defined 
in include/nuttx/compiler.h.  I don't know if the compiler will 
automatically generate the correct instruction to access the table 
across the bus bridge; I am not an AVR expert. There is a up_ function 
may need to be used to access the ROM table???


AVR Memory:  https://microchipdeveloper.com/8avr:memory
C Interface: 
http://ww1.microchip.com/downloads/en/AppNotes/Atmel-2575-C-Functions-for-Reading-and-Writing-to-Flash-Memory_ApplicationNote_AVR106.pdf


Hmm.. I notice that compiler.h defines IOBJ as __flash but the above 
document says:  "The datatypes are actually used as __flashor 
__farflashpointers (consequently 16 and 24 bit)."  That should be change 
to __farflash.




RE: Can we implement ctype functions through table?

2020-07-29 Thread spudaneco

I would consider option 3 to be the worst choice.  That could bloat can be 
enormous and unacceptable as I have seen in the past.  I saw growth by many 
kbyte in such cases. Not a good compromise.Sent from Samsung tablet.
 Original message From: Xiang Xiao  
Date: 7/29/20  12:54 AM  (GMT-06:00) To: dev@nuttx.apache.org Subject: RE: Can 
we implement ctype functions through table? The new option just make the 
situation worse. The same code works insome configurations, but breaks in other 
configurations.Since the standard confirmation is the most important principle 
forNuttX, we have three options:1.Implement ctype function with table and add 
256 byte to ROM2.Change macro to normal function and lose some 
performance3.Change macro to inline function and some old compilers may 
generatethe bloat codeall ctype functions are one line code, so option 3 may be 
a good compromise.> -Original Message-> From: David Sidrane 
> Sent: Tuesday, July 28, 2020 8:23 PM> To: 
dev@nuttx.apache.org> Subject: RE: Can we implement ctype functions through 
table?>> Xiang,>> If there is a small usage do you think flash will grow by 256 
bytes? I> would be surprised.>> Should you uses a config option?>> David>>> 
-Original Message-> From: Xiang Xiao 
[mailto:xiaoxiang781...@gmail.com]> Sent: Monday, July 27, 2020 10:40 PM> To: 
dev@nuttx.apache.org> Subject: RE: Can we implement ctype functions through 
table?>> Decorate the table with IPTR and access the element through 
up_romgetc,> just like printf series function.>> > -Original Message-> 
> From: Gregory Nutt > > Sent: Tuesday, July 28, 2020 
12:44 PM> > To: dev@nuttx.apache.org> > Subject: Re: Can we implement ctype 
functions through table?> >> > What about platforms like AVR?  That would not 
be a good decision for> > AVR since it is a harvard machine and cannot access 
data in ROM> > without special operations.> >> >> > On 7/27/2020 9:55 PM, Xiang 
Xiao wrote:> > > Hi all,> > > For example, here is isspace implementation:> > > 
#  define isspace(c) \> > >  ((c) == ' '  || (c) == '\t' || (c) == '\n' || 
(c) == '\r' || \> > >   (c) == '\f' || (c) == '\v')> > > The argument of c 
will evaluate 6 times, which make the following> > > code suddenly fail:> > > 
while (end != begin)> > >    {> > >  If (!isspace(*--end))> > >    {> > 
>   break;> > >    }> > >    }> > > But it work well with other 
libc implementation, because all other> > > libc utilize a table to classify  
the char type:> > > 
https://github.com/bminor/newlib/blob/master/newlib/libc/include/cty> > > pe> > 
> .h#L97> > > https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197> > 
> and the argument only need evaluate once.> > > So my question is: can we 
implement ctype functions through table to> > > improve the compatibility?> > > 
Yes, the table need take more 256 bytes ROM space, but the complex> > > 
expression used in NuttX also bloat the code size, especially> > > considering 
ctype function is used very frequently.> > >> > > Thanks> > > Xiang> > >

RE: Can we implement ctype functions through table?

2020-07-28 Thread Xiang Xiao
The new option just make the situation worse. The same code works in
some configurations, but breaks in other configurations.
Since the standard confirmation is the most important principle for
NuttX, we have three options:
1.Implement ctype function with table and add 256 byte to ROM
2.Change macro to normal function and lose some performance
3.Change macro to inline function and some old compilers may generate
the bloat code
all ctype functions are one line code, so option 3 may be a good compromise.


> -Original Message-
> From: David Sidrane 
> Sent: Tuesday, July 28, 2020 8:23 PM
> To: dev@nuttx.apache.org
> Subject: RE: Can we implement ctype functions through table?
>
> Xiang,
>
> If there is a small usage do you think flash will grow by 256 bytes? I
> would be surprised.
>
> Should you uses a config option?
>
> David
>
>
> -Original Message-
> From: Xiang Xiao [mailto:xiaoxiang781...@gmail.com]
> Sent: Monday, July 27, 2020 10:40 PM
> To: dev@nuttx.apache.org
> Subject: RE: Can we implement ctype functions through table?
>
> Decorate the table with IPTR and access the element through up_romgetc,
> just like printf series function.
>
> > -Original Message-
> > From: Gregory Nutt 
> > Sent: Tuesday, July 28, 2020 12:44 PM
> > To: dev@nuttx.apache.org
> > Subject: Re: Can we implement ctype functions through table?
> >
> > What about platforms like AVR?  That would not be a good decision for
> > AVR since it is a harvard machine and cannot access data in ROM
> > without special operations.
> >
> >
> > On 7/27/2020 9:55 PM, Xiang Xiao wrote:
> > > Hi all,
> > > For example, here is isspace implementation:
> > > #  define isspace(c) \
> > >  ((c) == ' '  || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
> > >   (c) == '\f' || (c) == '\v')
> > > The argument of c will evaluate 6 times, which make the following
> > > code suddenly fail:
> > > while (end != begin)
> > >{
> > >  If (!isspace(*--end))
> > >{
> > >   break;
> > >}
> > >}
> > > But it work well with other libc implementation, because all other
> > > libc utilize a table to classify  the char type:
> > > https://github.com/bminor/newlib/blob/master/newlib/libc/include/cty
> > > pe
> > > .h#L97
> > > https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197
> > > and the argument only need evaluate once.
> > > So my question is: can we implement ctype functions through table to
> > > improve the compatibility?
> > > Yes, the table need take more 256 bytes ROM space, but the complex
> > > expression used in NuttX also bloat the code size, especially
> > > considering ctype function is used very frequently.
> > >
> > > Thanks
> > > Xiang
> > >


RE: Can we implement ctype functions through table?

2020-07-28 Thread David Sidrane
Xiang,

If there is a small usage do you think flash will grow by 256 bytes? I would
be surprised.

Should you uses a config option?

David


-Original Message-
From: Xiang Xiao [mailto:xiaoxiang781...@gmail.com]
Sent: Monday, July 27, 2020 10:40 PM
To: dev@nuttx.apache.org
Subject: RE: Can we implement ctype functions through table?

Decorate the table with IPTR and access the element through up_romgetc, just
like printf series function.

> -Original Message-
> From: Gregory Nutt 
> Sent: Tuesday, July 28, 2020 12:44 PM
> To: dev@nuttx.apache.org
> Subject: Re: Can we implement ctype functions through table?
>
> What about platforms like AVR?  That would not be a good decision for AVR
> since it is a harvard machine and cannot access data in
> ROM without special operations.
>
>
> On 7/27/2020 9:55 PM, Xiang Xiao wrote:
> > Hi all,
> > For example, here is isspace implementation:
> > #  define isspace(c) \
> >  ((c) == ' '  || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
> >   (c) == '\f' || (c) == '\v')
> > The argument of c will evaluate 6 times, which make the following code
> > suddenly fail:
> > while (end != begin)
> >{
> >  If (!isspace(*--end))
> >{
> >   break;
> >}
> >}
> > But it work well with other libc implementation, because all other libc
> > utilize a table to classify  the char type:
> > https://github.com/bminor/newlib/blob/master/newlib/libc/include/ctype
> > .h#L97
> > https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197
> > and the argument only need evaluate once.
> > So my question is: can we implement ctype functions through table to
> > improve the compatibility?
> > Yes, the table need take more 256 bytes ROM space, but the complex
> > expression used in NuttX also bloat the code size, especially
> > considering ctype function is used very frequently.
> >
> > Thanks
> > Xiang
> >


RE: Can we implement ctype functions through table?

2020-07-27 Thread Xiang Xiao
Decorate the table with IPTR and access the element through up_romgetc, just 
like printf series function.

> -Original Message-
> From: Gregory Nutt 
> Sent: Tuesday, July 28, 2020 12:44 PM
> To: dev@nuttx.apache.org
> Subject: Re: Can we implement ctype functions through table?
> 
> What about platforms like AVR?  That would not be a good decision for AVR 
> since it is a harvard machine and cannot access data in
> ROM without special operations.
> 
> 
> On 7/27/2020 9:55 PM, Xiang Xiao wrote:
> > Hi all,
> > For example, here is isspace implementation:
> > #  define isspace(c) \
> >  ((c) == ' '  || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
> >   (c) == '\f' || (c) == '\v')
> > The argument of c will evaluate 6 times, which make the following code 
> > suddenly fail:
> > while (end != begin)
> >{
> >  If (!isspace(*--end))
> >{
> >   break;
> >}
> >}
> > But it work well with other libc implementation, because all other libc 
> > utilize a table to classify  the char type:
> > https://github.com/bminor/newlib/blob/master/newlib/libc/include/ctype
> > .h#L97
> > https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197
> > and the argument only need evaluate once.
> > So my question is: can we implement ctype functions through table to 
> > improve the compatibility?
> > Yes, the table need take more 256 bytes ROM space, but the complex
> > expression used in NuttX also bloat the code size, especially considering 
> > ctype function is used very frequently.
> >
> > Thanks
> > Xiang
> >



Re: Can we implement ctype functions through table?

2020-07-27 Thread Gregory Nutt
What about platforms like AVR?  That would not be a good decision for 
AVR since it is a harvard machine and cannot access data in ROM without 
special operations.



On 7/27/2020 9:55 PM, Xiang Xiao wrote:

Hi all,
For example, here is isspace implementation:
#  define isspace(c) \
 ((c) == ' '  || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
  (c) == '\f' || (c) == '\v')
The argument of c will evaluate 6 times, which make the following code suddenly 
fail:
while (end != begin)
   {
 If (!isspace(*--end))
   {
  break;
   }
   }
But it work well with other libc implementation, because all other libc utilize 
a table to classify  the char type:
https://github.com/bminor/newlib/blob/master/newlib/libc/include/ctype.h#L97
https://github.com/bminor/glibc/blob/master/ctype/ctype.h#L197
and the argument only need evaluate once.
So my question is: can we implement ctype functions through table to improve 
the compatibility?
Yes, the table need take more 256 bytes ROM space, but the complex expression 
used in NuttX also bloat the code size, especially
considering ctype function is used very frequently.

Thanks
Xiang