Author Topic: GCC global variables  (Read 2906 times)

0 Members and 1 Guest are viewing this topic.

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 14551
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: GCC global variables
« Reply #25 on: August 04, 2019, 02:55:46 am »
Right, M4*.  But 50 or 75MHz is still quite a lot of CPU. :)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1344
  • Country: fi
    • My home page and email address
Re: GCC global variables
« Reply #26 on: August 04, 2019, 05:07:57 am »
In this particular situation, I like to create globals.h that is included by all C source files accessing any of those globals:
Code: [Select]

 #ifndef   GLOBALS_H
 #define   GLOBALS_H

 #ifdef   MAIN
 #define  EXTERN
 #else
 #define  EXTERN  extern
 #endif

EXTERN volatile int  myvar;

 #undef  EXTERN
 #endif /* GLOBALS_H */

and in the source file containing main() , have #define MAIN before anys.
This way, there is only one declaration, and one definition in the compilation unit containing main().  Makes maintenance simple.

If you have atomic variables, I like to declare them in atomics.h, define in atomics.c, and have atomics.h include static inline accessor functions using GCC atomic builtins.  For example, atomics.h:
Code: [Select]

 #ifndef   ATOMICS_H
 #define   ATOMICS_H

extern volatile unsigned int  mycounter_value;

static inline unsigned int mycounter(void)
{
    return __atomic_load_n(&mycounter_value, __ATOMIC_SEQ_CST);
}

static inline unsigned int mycounter_postinc(void)
{
    return __atomic_fetch_add(&mycounter_value, 1, __ATOMIC_SEQ_CST);
}

static inline unsigned int mycounter_predec(void)
{
    return __atomic_sub_fetch(&mycounter_value, 1, __ATOMIC_SEQ_CST);
}

 #endif /* ATOMICS_H */

and atomics.c:
Code: [Select]
"atomics.h"

volatile unsigned int  mycounter_value;
You only use the accessor functions, and not mycounter_value directly, elsewhere in your code.  Makes porting code to other compilers easier, too -- although ICC and clang support those as well.

Technically, it is not necessary to mark mycounter_value volatile, because it is not to be accessed directly by anything other than the static inline functions, and they ensure it is fetched; but having it marked volatile does not hurt.

If you have mixed C/C++ sources, add extern "C" { and } guards as usual.  If you use C++, use native atomics.  If you need the code to compile on older versions of GCC, use the legacy __sync builtins instead.



(I wish someone would disable the damn stuff in this forum, so that C preprocessor statements would not be indented and linkified.  |O)
 

Offline nigelwright7557

  • Regular Contributor
  • *
  • Posts: 214
  • Country: gb
    • Murton-Pike Systems
Re: GCC global variables
« Reply #27 on: August 04, 2019, 05:25:15 am »
what is an atomic declaration?
what is re-ordering evaluation.
On an 8 bit machine accessing 16 or 32 bit variables is not atomic. That is, they will usually be accessed as two or four 8 bit chunks, and the variable might be changed by other code between these accesses.

The re-ordering issue is that you should not assume that things will be executed in the order they occur in your source code. Variables may be accessed in a very different order, typically to keep a better flow through the machine's pipelines.

Atomic usually means done in one instruction.
Havoc comes when its done in 3 instructions like a read, modify,write sequence.
You get an interrupt half way through that modifies the same variable.
The interrupt ends and the old variable is used in the main code.


PCBCAD51/PCBCAD360/PCBCAD720 PCB design software https://www.murtonpikesystems.co.uk
 

Offline Whales

  • Frequent Contributor
  • **
  • Posts: 921
  • Country: au
    • Halestrom
Re: GCC global variables
« Reply #28 on: August 04, 2019, 05:30:11 am »
I encountered similar issues once before, but on win32.

A (DLL) library I was using had globals.  My program could access them directly and through getter/setter funcs.

That didn't go too well.  Both my program and the DLL ended up with completely different "views" or "copies" of the globals to play with.  In my case I think it was also because of the compiler I was using (TCC).

I will +1 the suggestion of doing a complete from-scratch build.  Delete all of the temporary object files, so every file is forced to rebuild. 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 9391
  • Country: my
  • reassessing directives...
Re: GCC global variables
« Reply #29 on: August 04, 2019, 06:20:43 am »
That didn't go too well.  Both my program and the DLL ended up with completely different "views" or "copies" of the globals to play with.  In my case I think it was also because of the compiler I was using (TCC).
have you made a success on sharing dll global variable amongs win32 exes? because what i understand, each exe (even multiple instances of the same exe) will always make a copy of their own to avoid multi threading race problem or malicious access from another program.
« Last Edit: August 04, 2019, 08:08:46 am by Mechatrommer »
if something can select, how cant it be intelligent? if something is intelligent, how cant it exist?
 

Online magic

  • Super Contributor
  • ***
  • Posts: 1625
  • Country: pl
Re: GCC global variables
« Reply #30 on: August 04, 2019, 07:05:50 am »
Don't forget what volatile doesn't guarantee about, for example, re-ordering evaluation.
Damnit, you scared me :P

It's not that bad actually, from current GCC manual at https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html
Quote
The standard encourages compilers to refrain from optimizations concerning accesses to volatile objects, but leaves it implementation defined as to what constitutes a volatile access. The minimum requirement is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses that occur between sequence points, but cannot do so for accesses across a sequence point.

For those wondering, sequence points are a well-defined concept in C whose exact definition can be looked up, I guess. It includes different expressions, so
Code: [Select]
extern volatile int a, b;
a++;
b++;
executes as one expects and incremented a before b.

This however is not guaranteed to be so:
Code: [Select]
return a++ + b++;
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #31 on: August 04, 2019, 07:28:25 am »
Another option, if a somewhat heavy-handed one, is to put all the variables into one .c file, and expose only accessor functions.  This is equivalent to the OOP practice of private variables, private helper functions, and public getters/setters.

Probably not be worthwhile on a small or embedded project, but then again, embedded CPUs are awfully powerful these days; a Cortex M0 at 160MHz doing the job of a PIC at 8MHz say?  Lots of room for verbosity. :)

At higher optimisation levels, won't the compiler inline such getter/setter functions? Even the Java HotSpot runtime does that!
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 9391
  • Country: my
  • reassessing directives...
Re: GCC global variables
« Reply #32 on: August 04, 2019, 08:04:44 am »
yup just a taboo version of excessive exposure. accessor functions in OOP is provided so the class can make other housekeeping task when access/modifying a variable member, if the function is simply = the var to be accessed, it will be much simpler or equally as to make the variable public.
if something can select, how cant it be intelligent? if something is intelligent, how cant it exist?
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #33 on: August 04, 2019, 08:08:24 am »
yup just a taboo version of excessive exposure. accessor functions in OOP is provided so the class can make other housekeeping task when access/modifying a variable member, if the function is simply = the var to be accessed, it will be much simpler or equally as to make the variable public.

You miss the point. Get the compiler to do the optimisations, safely, transparently, and (with HotSpot) only where it really benefits the application.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 9391
  • Country: my
  • reassessing directives...
Re: GCC global variables
« Reply #34 on: August 04, 2019, 08:11:02 am »
such minor optimisation is moot in this age, what we need is a working application as intended...
if something can select, how cant it be intelligent? if something is intelligent, how cant it exist?
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 14551
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: GCC global variables
« Reply #35 on: August 04, 2019, 08:15:19 am »
At higher optimisation levels, won't the compiler inline such getter/setter functions? Even the Java HotSpot runtime does that!

Yes, if they're small enough and/or used infrequently enough that it's viable of course.  Though putting them between modules may prohibit that, depending on if they're in the same build/link environment (versus an object library, or dynamic for that matter), and depending on what kind of optimizations are allowed (link-time optimization doesn't work for a library, but does for a complete

Even if it optimizes down to the same thing (literally "x = y" one-liners), the semantics may be different from an all-shared build, and can be safer from a programming standpoint (it's harder for any one .c file to break everything?), if not from an execution standpoint (ideally, different modules might be protected from each other explicitly in separate memory spaces; though that's more at the scale of interprocess, not intermodule, programming).

But this is very much beyond the limits of my knowledge, as far as nuanced semantics and optimizations and memory management and operating systems are concerned.  I'll leave the precise logic to those in the know. :)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #36 on: August 04, 2019, 08:27:41 am »
At higher optimisation levels, won't the compiler inline such getter/setter functions? Even the Java HotSpot runtime does that!

Yes, if they're small enough and/or used infrequently enough that it's viable of course.  Though putting them between modules may prohibit that, depending on if they're in the same build/link environment (versus an object library, or dynamic for that matter), and depending on what kind of optimizations are allowed (link-time optimization doesn't work for a library, but does for a complete

Even if it optimizes down to the same thing (literally "x = y" one-liners), the semantics may be different from an all-shared build, and can be safer from a programming standpoint (it's harder for any one .c file to break everything?), if not from an execution standpoint (ideally, different modules might be protected from each other explicitly in separate memory spaces; though that's more at the scale of interprocess, not intermodule, programming).

But this is very much beyond the limits of my knowledge, as far as nuanced semantics and optimizations and memory management and operating systems are concerned.  I'll leave the precise logic to those in the know. :)

Regrettably such "precise logic" is an oxymoron, like "military intelligence". Both do exist, but they aren't what an external observer might expect or comprehend :(

A C compiler can only guess at what is sufficiently small and/or frequent to inline, and is often hobbled by the possibility of aliasing. Java Hotspot measures what is actually frequently used, and there can be no aliasing at that level.
« Last Edit: August 04, 2019, 08:29:46 am by tggzzz »
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 14236
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: GCC global variables
« Reply #37 on: August 04, 2019, 08:53:28 am »
Well for this application it's not much of a problem because of what it does. The time variable should be 8 bit as it's only counting to 10. The other interrupt accessed variables are a tacho which for this application is not an issue. Speed adjustments are done one step at a time in small steps with no complicated predictive control loop. The speed control algorithm just checks if the speed is higher or lower than threshold and nudges the control signal up or down. so if an error is made due to the variable being modified part way through evaluation it would mean a tiny speed nudge up or down more than wanted but this would not be a problem and there is an amount of dithering already intentionally put into the speed control so it would not even show.

It looks like my intention to move to SAMC ARM devices a good idea as much of these problems go away unless the variable is over 32bit and code will be more efficient as the time is spent "doing it" rather than trying to work around limitations of the hardware.
https://www.simonselectronics.co.uk/shop
Varied stock of test instruments and components including EEVblog gear and Wurth Elektronik Books.
Also, if you want to get ripped off: https://www.ebay.co.uk/usr/simons_electronics?_trksid=p2047675.l2559
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 14551
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: GCC global variables
« Reply #38 on: August 04, 2019, 09:05:02 am »
Regrettably such "precise logic" is an oxymoron, like "military intelligence". Both do exist, but they aren't what an external observer might expect or comprehend :(

A C compiler can only guess at what is sufficiently small and/or frequent to inline, and is often hobbled by the possibility of aliasing. Java Hotspot measures what is actually frequently used, and there can be no aliasing at that level.

Well no, it doesn't guess, it actually checks, it does it and compares on the metric, whatever that is (CPU cycles, object size..).

At least that's what I understand from GCC's documentation, what of it I've read.  I think... they do two passes?  One for assembler, one for linkage (if enabled).

I forget when clang is supposed to do optimization, if it's before LLVM generation, or after?  AFAIK there's a lot of smarts in there that would be able to do these optimizations either way though.

There are clear rules that all of these things are run by (they're literally just more dumb computer programs :P ), but they're really only well known to those very deeply familiar with the quirks and processes of compiler internals, or compiler devs themselves.  Or, those that have run into the edge cases here and there, and found that it's actually a bit of semantics that they didn't mean to put in there but actually did... :)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 2182
  • Country: fi
Re: GCC global variables
« Reply #39 on: August 04, 2019, 09:05:43 am »
Instead of exposing all program-wide global variables in the headers, I often opt for declaring them where I need them. This gives the declaration a smaller scope. Like this:

void do_something()
{
      ...
      ...
      extern volatile int battery_voltage;
      battery_voltage used right here;
      ...
      ...
}

Since heavily relying on such globals would get messy soon, having the declaration in plain sight helps the reader to understand that this variable indeed is:
A) defined in another module,
B) a volatile,

C) likely a hack, which could be replaced by something better

I do this especially when I feel like it's a temporary hack. Very local declaration documents it as such, and keeps affected area as small as possible. If I find myself then needing to declare it everywhere, I need to rethink.

I only add the externs to the header files if I feel like I'm comfortable with them being there. I.e., it's really used everywhere, I remember what it is and why it exists - and why it's not behind access functions. For example, a global, very widely and often used millisecond counter, named properly.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 2182
  • Country: fi
Re: GCC global variables
« Reply #40 on: August 04, 2019, 09:09:49 am »
A C compiler can only guess at what is sufficiently small and/or frequent to inline, and is often hobbled by the possibility of aliasing.

No need to guess, modern C compilers (including GCC) have built-in instrumentation techniques. Basically, you compile it with a suitable flag, it injects instrumentation code, you run the program, and it outputs a statistic blob, which you input for the next compilation. This guides inlining, but also branch probabilities.

Without such instrumentation, it would be guessing, yes.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 18553
  • Country: nl
    • NCT Developments
Re: GCC global variables
« Reply #41 on: August 04, 2019, 09:40:15 am »
Global variables cannot always be avoided. What I usually do is put them in one or more structs.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #42 on: August 04, 2019, 10:21:08 am »
A C compiler can only guess at what is sufficiently small and/or frequent to inline, and is often hobbled by the possibility of aliasing.

No need to guess, modern C compilers (including GCC) have built-in instrumentation techniques. Basically, you compile it with a suitable flag, it injects instrumentation code, you run the program, and it outputs a statistic blob, which you input for the next compilation. This guides inlining, but also branch probabilities.

Without such instrumentation, it would be guessing, yes.

Oh, I didn't realise it was almost catching up with Java in that respect. They probably took note of HP's Dynamo experiment in 1999.

Now all it has to achieve is to do that automatically when you run the code on a different processor, e.g. one that didn't exist when the compilation was done. Or when the library blob (without source) is linked with an application and other library blobs.

Aliasing requires pessimisation.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #43 on: August 04, 2019, 10:28:02 am »
Regrettably such "precise logic" is an oxymoron, like "military intelligence". Both do exist, but they aren't what an external observer might expect or comprehend :(

A C compiler can only guess at what is sufficiently small and/or frequent to inline, and is often hobbled by the possibility of aliasing. Java Hotspot measures what is actually frequently used, and there can be no aliasing at that level.

Well no, it doesn't guess, it actually checks, it does it and compares on the metric, whatever that is (CPU cycles, object size..).

At least that's what I understand from GCC's documentation, what of it I've read.  I think... they do two passes?  One for assembler, one for linkage (if enabled).

I forget when clang is supposed to do optimization, if it's before LLVM generation, or after?  AFAIK there's a lot of smarts in there that would be able to do these optimizations either way though.

There are clear rules that all of these things are run by (they're literally just more dumb computer programs :P ), but they're really only well known to those very deeply familiar with the quirks and processes of compiler internals, or compiler devs themselves.  Or, those that have run into the edge cases here and there, and found that it's actually a bit of semantics that they didn't mean to put in there but actually did... :)

Many experienced and intelligent people have been bitten more than once by C.

I'd be interested to see understand how a library binary blob (i.e. without source) is optimised when linked with other library blobs and an application. Bonus points for when the compiler version/optimisation levels are different or it is a newly released processor :)

But I suspect that kind of thing is why .NET updates take your machine offline for so long :)
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: GCC global variables
« Reply #44 on: August 04, 2019, 11:44:41 am »
GCC atomic builtins

I vote for this solution. It's the same used in multicore libraries, and it does the job.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1899
  • Country: ca
Re: GCC global variables
« Reply #45 on: August 04, 2019, 01:25:16 pm »
This guides inlining, but also branch probabilities.

Modern CPUs do this at run time even better and you don't even need to lift a finger.

However, the abundance of bloated software tells us that compiler/CPU optimizations are powerless against human bloat.
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 10695
  • Country: gb
    • Having fun doing more, with less
Re: GCC global variables
« Reply #46 on: August 04, 2019, 01:37:27 pm »
This guides inlining, but also branch probabilities.

Modern CPUs do this at run time even better and you don't even need to lift a finger.

Only for recently executed branches, and at the expense of leaking information across security domain barriers.

The latter has meant that (x86) microcode updates have had to disable some optimisations, and reduced performance. It will be interesting to see if such optimisations survive in the future.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 2039
  • Country: us
Re: GCC global variables
« Reply #47 on: August 04, 2019, 02:23:34 pm »

Volatile doesn't handle this at all.  Volatile simply makes the compiler emit code to re-evaluate a variable every time through a loop.  Ordinarily, a variable would be considered 'loop invariant' if it isn't changed inside the loop and evaluated just once, probably before entering the loop.

That's not actually what volatile does. Volatile means that everyemor load and store in the C "virtual machine" will actually happen and preserve order.  So one outcome is that variables accessed in a loop will be fetched from memory every iteration, but it does more than that.

In practice, all C compliers guarantee that variables of certian types will be loaded and stored with a single instruction based on the target ISA.  On a single core CPU that is sufficient to make them atomic, including interrupt context.  This also works for signals if your platform supports them.  So as long as you know what sizes your platform supports you can share volatile variables between main thread and interrupt context.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 4225
  • Country: fr
Re: GCC global variables
« Reply #48 on: August 04, 2019, 02:30:54 pm »
With regard to the timer variable it needs up-counting by the interrupt routine, testing by the main if statement which could be done with what yo describe but it needs zeroing again by the "if"s code.

Which in the same approach, can be perfectly done adding another function that resets the counter. And call that instead of directly assigning "0" to the variable.

 :-+ Using small functions to get/set the value of variables is a much better idea than having a huge clump of global variables.  Also I don't see any mention of shadowing, perhaps there is another variable of the same name which is closer in scope to the function using it, often caused by beginners using header files to define variables.

Yeah, many benefits of doing that. Would be too long to list them all. And of course, it must not be overdone either: as always, common sense helps.

But basically, accessing a variable only within a single source file makes things much clearer, hides the internals of a given module, avoids a lot of possible bugs (the possibility of modifying a variable all over the place can get very nasty for maintenance, and a source of potentially horrible bugs), makes modifications of said module much easier to do, makes you code in a much more structured and modular way (which improves many things including reusability), etc.

I've noticed many people still have a very hard time thinking "modular" when programming, which is unfortunate, and only force themselves doing so (but not necessarily that well) using specific languages. You can write very decent modular code in C. Just because it doesn't include fancy OOP features doesn't mean you should write piles of spaghetti with it.

 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 6909
  • Country: us
Re: GCC global variables
« Reply #49 on: August 04, 2019, 02:58:36 pm »
In practice, all C compliers guarantee that variables of certian types will be loaded and stored with a single instruction based on the target ISA.  On a single core CPU that is sufficient to make them atomic, including interrupt context.  This also works for signals if your platform supports them.  So as long as you know what sizes your platform supports you can share volatile variables between main thread and interrupt context.

Well, you can't store a 32 bit value in an 8 bit memory in one cycle no matter what the data type.  Omitting 'volatile' because some particular architecture supports the full data width makes porting a bit more of an issue.

I have been blocking critical operations with disable and enable of interrupts for a very long time.  It's pretty much guaranteed to work and it also happens to be the way most RTOSes deal with the issue.  Here is how FreeRTOS handles it:

https://www.freertos.org/taskENTER_CRITICAL_taskEXIT_CRITICAL.html

You simply can't depend on the compiler.  There is likely to be differences in the code sequence between -O0 and -O3 optimization levels.  The compiler writers are very good but sometimes we out-clever ourselves.  And who's to say the same compiler (or even toolchain) will be used on the code somewhere down the line.

How many times has the programmer been caught out with a 'spin loop' (delay) that gets optimized away?  It happens all the time.  "How come my time delay code doesn't work?".
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf