Electronics-Related.com
Forums

KiCad Spice, Anyone Tried It?

Started by Ricketty C June 2, 2020
On 2020-06-05 05:48, Tom Gardner wrote:
> On 05/06/20 10:25, Phil Hobbs wrote: >> On 2020-06-05 05:07, Tom Gardner wrote: >>> On 05/06/20 09:45, Phil Hobbs wrote: >>>> On 2020-06-05 04:05, David Brown wrote: >>>>> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>>>>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>>>>> <david.brown@hesbynett.no> wrote: >>>>>> >>>>>> >>>>>>>> >>>>>>>> That's what I have to do, use an oscilloscope to show >>>>>>>> programmers what >>>>>>>> their code does. You can often relate the pulse widths to paths >>>>>>>> through the code. >>>>>>>> >>>>>>> >>>>>>> A scope can be a fine tool for measuring code performance.&nbsp; I >>>>>>> like to >>>>>>> make sure there are a few test pins on our boards that can be >>>>>>> connected >>>>>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>>>>> programmers understand how to instrument code for such measurements, >>>>>>> unfortunately. >>>>>> >>>>>> Raise a port pin at the start of the routine, and drop it at the end. >>>>>> Maybe invert it a couple of times, at interesting points. >>>>> >>>>> And how do you know that you are raising it at the /real/ start of >>>>> the routine, and dropping it at the /real/ end of the routine? >>>>> I've seen people write code like : >>>>> >>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>>> >>>>> without realising that the compiler (and processor, for more >>>>> advanced cpus) can re-order a lot of that and make the timing >>>>> seriously unrealistic. >>>> >>>> All the embedded stuff I recall doing in C/C++ defines the various >>>> port registers as volatile, so the compiler can't play games like that. >>>> >>>> How would you ever make embedded code work if the compiler could >>>> randomly optimize away or reorder port accesses?&nbsp; You could never >>>> even poll a hardware flag. >>> >>> I await David Brown's expert comment, but from >>> https://en.cppreference.com/w/c/language/volatile >>> >>> "This means that within a single thread of execution, a volatile >>> access cannot be optimized out or reordered relative to another >>> visible side effect that is separated by a sequence point from the >>> volatile access." >> >> The end of a statement is a sequence point. > > That helps, provided the code is written in a sane > /simple/ way. > > I'm it is possible to create cases which are > problematic. I've seen some remarkably bad code > in my time :(
Me too, but DB was just blowing smoke at JL with that silly example. Cheers Phil Hobbs -- Dr Philip C D Hobbs Principal Consultant ElectroOptical Innovations LLC / Hobbs ElectroOptics Optics, Electro-optics, Photonics, Analog Electronics Briarcliff Manor NY 10510 http://electrooptical.net http://hobbs-eo.com
On 2020-06-05 05:54, Phil Hobbs wrote:
> On 2020-06-05 05:40, David Brown wrote: >> On 05/06/2020 10:54, Phil Hobbs wrote: >>> On 2020-06-04 22:58, whit3rd wrote: >>>> On Thursday, June 4, 2020 at 9:14:43 AM UTC-7, >>>> jla...@highlandsniptechnology.com wrote: >>>>> On Thu, 4 Jun 2020 16:10:35 +0100, Tom Gardner >>>>> <spamjunk@blueyonder.co.uk> wrote: >>>>> >>>>>> On 04/06/20 15:26, David Brown wrote: >>>> >>>>>>> If someone asked me to make a 5th order polynomial for >>>>>>> calibration, I'd say >>>>>>> "No.&nbsp; Let's look at the system and see how to handle it >>>>>>> /properly/". &nbsp;Any >>>>>>> polynomial above 3rd order is likely (not guaranteed, but likely) >>>>>>> to be wrong - >>>>>>> over-fitted, unstable, or both. >>>> >>>>> The official ITS thermocouple voltage-temperature equations range from >>>>> 8th order to 14th order for various thermocouples. We make both >>>>> thermocouple acquisition and simulation products. If anyone refused to >>>>> implement the ITS equations, of course I'd fire them, for stupidity if >>>>> nothing else. >>>> >>>> But the ITS equations are a temperature scale, that apply to all >>>> thermocouples >>>> of a type.&nbsp;&nbsp; Calibration includes instrument peculiarities that >>>> aren't known >>>> except after construction of the whole instrument.&nbsp;&nbsp;&nbsp; Not >>>> all calibrations have continuous, well-behaved functional&nbsp; nature, >>>> but all polynomials do. >>>> >>>> The general class of calibrations isn't automatically fit to a >>>> polynomial. >>>> >>> >>> Any actual thermocouple pair has a well-behaved, gently nonlinear >>> characteristic V(T1,T2) that is a good match to any well-designed >>> polynomial, spline, or rational-function fit technique.&nbsp; (You can >>> even use rational trig functions, knock yourself out.) >>> >>> It really isn't rocket science to fit a smooth nonlinearity of at >>> most a few tens of percent over a wide temperature range, to any >>> accuracy remotely required for temperature measurements. >>> >>> Of course, if you do the calibration sufficiently badly, you can make >>> problems for yourself, but they aren't specifically mathematical >>> problems. >>> >> >> My impression of Whit's post was that the calibration in a real system >> might be for compensating for tolerances of bias resistors, parasitic >> effects of ESD protection devices, and other board-level effects.&nbsp; The >> calibration is likely to remain a smooth function that (unless you've >> really made a mess of the hardware), but it may no longer be a good >> fit for the polynomial picked by the thermocouple manufacturer.&nbsp; So >> fitting to a cubic spline (or other suitable function, as you >> mentioned) based on real-life board measurements is going to make more >> sense than trying to force usage of the original ITS polynomial.&nbsp; (If >> you are not basing it on measurements, it is not calibration.) >> > > We hope that the published coefficients are based on some actual > calibration, because AFAIK there's no sufficiently accurate > first-principles calculation available that applies to real devices. > > Resistor errors, offset voltages, leakage, and so on are normally > smallish smooth effects of the sort that cause no problems for > polynomial fitting. > > > I claim that polynomial fits get into trouble with: > > discontinuities in value or low-order derivatives; > > asymptotes (a biggie); > > large changes in local behaviour, e.g. localized oscillations; > > crappy fitting procedures, e.g. use of noisy data; > > full stop. >
And ill-conditioned basis sets, of course, but that's not a fundamental problem with polynomials per se. Cheers Phil Hobbs -- Dr Philip C D Hobbs Principal Consultant ElectroOptical Innovations LLC / Hobbs ElectroOptics Optics, Electro-optics, Photonics, Analog Electronics Briarcliff Manor NY 10510 http://electrooptical.net http://hobbs-eo.com
On 05/06/2020 10:45, Phil Hobbs wrote:
> On 2020-06-05 04:05, David Brown wrote: >> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>> <david.brown@hesbynett.no> wrote: >>> >>> >>>>> >>>>> That's what I have to do, use an oscilloscope to show programmers what >>>>> their code does. You can often relate the pulse widths to paths >>>>> through the code. >>>>> >>>> >>>> A scope can be a fine tool for measuring code performance.&nbsp; I like to >>>> make sure there are a few test pins on our boards that can be connected >>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>> programmers understand how to instrument code for such measurements, >>>> unfortunately. >>> >>> Raise a port pin at the start of the routine, and drop it at the end. >>> Maybe invert it a couple of times, at interesting points. >> >> And how do you know that you are raising it at the /real/ start of the >> routine, and dropping it at the /real/ end of the routine?&nbsp; I've seen >> people write code like : >> >> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >> >> without realising that the compiler (and processor, for more advanced >> cpus) can re-order a lot of that and make the timing seriously >> unrealistic. > > All the embedded stuff I recall doing in C/C++ defines the various port > registers as volatile, so the compiler can't play games like that. >
That's the common misunderstanding. "volatile" tells the compiler (but not the processor, write buffers, cache, memory buffers, or any other hardware) that this particular access can't be omitted or re-ordered with respect to other volatile accesses or "observable behaviour". But it says /nothing/ about re-ordering with respect to non-observable behaviour, such as calculations. Supposing you want to find out how much time your cpu takes for a multiply instruction. You might write code like this: // Obviously this would match a real register address extern volatile unsigned char pin; extern unsigned int testresult; void testmults(void) { pin = 1; unsigned int t = 1; for (unsigned int x = 1; x <= 1000; x++) { t *= x; } pin = 0; testresult = t; } Set the pin high - it's a volatile access, and the compiler can't omit it or reorder it. Do the calculations. Set the pin low. What can go wrong? You've been smart enough to "use" the calculation result, so that the compiler doesn't remove the loop entirely. (Not every programmer would think of that.) The compiler is free to re-organise this code in any way it wants, as long as pin is set to 1 before it is set to 0, and as long as "testresult" gets the right value in the end. It can generate code equivalent to: void testmults(void) { pin = 1; pin = 0; unsigned int t = 1; for (unsigned int x = 1; x <= 1000; x++) { t *= x; } testresult = t; } or void testmults(void) { testresult = 0; // Since that is the answer pin = 1; pin = 0; } or all sorts of other possibilities. The general solution to this is to make sure the calculation depends on an initial volatile read, and the result is used in a volatile write - that lets you control where the calculation is done with respect to the volatile pin control. So you could use: static const volatile unsigned int vol_one = 1; static volatile unsigned int vol_result; void testmults(void) { pin = 1; unsigned int t = vol_one; for (unsigned int x = 1; x <= 1000; x++) { t *= x; } vol_result = t; pin = 0; testresult = t; } (It is possible to enforce orderings without needing extra memory reads and writes or instructions using empty gcc inline assembly in careful ways.) Do compilers do this kind of re-arrangement in practice? Yes, they do - but usually only if there is a good reason for it. I've certainly seen bits of "measured" code re-arranged with respect to the instrumentation. The same problem also occurs with interrupt-disable code. A well-established example can be seen here: <https://www.nongnu.org/avr-libc/user-manual/optimization.html> Here, the original author had thought that a "memory barrier" would solve any such re-arrangement problems - but the example shows it is not the case. And that's all just for the compiler's viewpoint. Hardware can have a big effect (I'm sure you can imagine) - are you measuring the calculation time, or the cache miss time, or is the time dependent on the state of the write-back buffers? Usually the solution there is to do lots of samples so you have an average timing.
> How would you ever make embedded code work if the compiler could > randomly optimize away or reorder port accesses?&nbsp; You could never even > poll a hardware flag. >
The compiler can't re-order the volatile parts - but it can re-order everything else. A very common misunderstanding about volatile is that people often think volatile accesses also order other code and accesses - they do not. (C11/C++11 atomic accesses can affect the order of other memory accesses, but not the order of code and calculations.)
On 05/06/2020 11:57, Phil Hobbs wrote:
> On 2020-06-05 05:54, Phil Hobbs wrote: >> On 2020-06-05 05:40, David Brown wrote: >>> On 05/06/2020 10:54, Phil Hobbs wrote: >>>> On 2020-06-04 22:58, whit3rd wrote: >>>>> On Thursday, June 4, 2020 at 9:14:43 AM UTC-7, >>>>> jla...@highlandsniptechnology.com wrote: >>>>>> On Thu, 4 Jun 2020 16:10:35 +0100, Tom Gardner >>>>>> <spamjunk@blueyonder.co.uk> wrote: >>>>>> >>>>>>> On 04/06/20 15:26, David Brown wrote: >>>>> >>>>>>>> If someone asked me to make a 5th order polynomial for >>>>>>>> calibration, I'd say >>>>>>>> "No.&nbsp; Let's look at the system and see how to handle it >>>>>>>> /properly/". &nbsp;Any >>>>>>>> polynomial above 3rd order is likely (not guaranteed, but >>>>>>>> likely) to be wrong - >>>>>>>> over-fitted, unstable, or both. >>>>> >>>>>> The official ITS thermocouple voltage-temperature equations range >>>>>> from >>>>>> 8th order to 14th order for various thermocouples. We make both >>>>>> thermocouple acquisition and simulation products. If anyone >>>>>> refused to >>>>>> implement the ITS equations, of course I'd fire them, for >>>>>> stupidity if >>>>>> nothing else. >>>>> >>>>> But the ITS equations are a temperature scale, that apply to all >>>>> thermocouples >>>>> of a type.&nbsp;&nbsp; Calibration includes instrument peculiarities that >>>>> aren't known >>>>> except after construction of the whole instrument.&nbsp;&nbsp;&nbsp; Not >>>>> all calibrations have continuous, well-behaved functional&nbsp; nature, >>>>> but all polynomials do. >>>>> >>>>> The general class of calibrations isn't automatically fit to a >>>>> polynomial. >>>>> >>>> >>>> Any actual thermocouple pair has a well-behaved, gently nonlinear >>>> characteristic V(T1,T2) that is a good match to any well-designed >>>> polynomial, spline, or rational-function fit technique.&nbsp; (You can >>>> even use rational trig functions, knock yourself out.) >>>> >>>> It really isn't rocket science to fit a smooth nonlinearity of at >>>> most a few tens of percent over a wide temperature range, to any >>>> accuracy remotely required for temperature measurements. >>>> >>>> Of course, if you do the calibration sufficiently badly, you can >>>> make problems for yourself, but they aren't specifically >>>> mathematical problems. >>>> >>> >>> My impression of Whit's post was that the calibration in a real >>> system might be for compensating for tolerances of bias resistors, >>> parasitic effects of ESD protection devices, and other board-level >>> effects.&nbsp; The calibration is likely to remain a smooth function that >>> (unless you've really made a mess of the hardware), but it may no >>> longer be a good fit for the polynomial picked by the thermocouple >>> manufacturer.&nbsp; So fitting to a cubic spline (or other suitable >>> function, as you mentioned) based on real-life board measurements is >>> going to make more sense than trying to force usage of the original >>> ITS polynomial.&nbsp; (If you are not basing it on measurements, it is not >>> calibration.) >>> >> >> We hope that the published coefficients are based on some actual >> calibration, because AFAIK there's no sufficiently accurate >> first-principles calculation available that applies to real devices. >> >> Resistor errors, offset voltages, leakage, and so on are normally >> smallish smooth effects of the sort that cause no problems for >> polynomial fitting. >> >> >> I claim that polynomial fits get into trouble with: >> >> discontinuities in value or low-order derivatives; >> >> asymptotes (a biggie); >> >> large changes in local behaviour, e.g. localized oscillations; >> >> crappy fitting procedures, e.g. use of noisy data; >> >> full stop. >> > > And ill-conditioned basis sets, of course, but that's not a fundamental > problem with polynomials per se. >
Agreed. You might add over-fitting to the list, but that is a problem of misunderstanding the use of polynomials rather than the polynomial itself. And even with good basis sets, high-order polynomials can be harder to evaluate well on limited processors than low-order splines (cubic or linear). Again, that is not a fundamental problem with polynomials, but it is a practical issue. A single polynomial will also be difficult to fit if there is a curve which simply doesn't match well with a reasonable degree polynomial. An exponential decay will look smooth, but need a surprisingly high degree polynomial to get a good approximation. You'll also have trouble with a curve with distinct regions, which can occur as different physical effects dominate in different parts of the graph. None of this excludes the possibility of using a single high-order polynomial. But it can make it a lot less practical in comparison to a low-order spline.
On 05/06/2020 11:25, Phil Hobbs wrote:
> On 2020-06-05 05:07, Tom Gardner wrote: >> On 05/06/20 09:45, Phil Hobbs wrote: >>> On 2020-06-05 04:05, David Brown wrote: >>>> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>>>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>>>> <david.brown@hesbynett.no> wrote: >>>>> >>>>> >>>>>>> >>>>>>> That's what I have to do, use an oscilloscope to show programmers >>>>>>> what >>>>>>> their code does. You can often relate the pulse widths to paths >>>>>>> through the code. >>>>>>> >>>>>> >>>>>> A scope can be a fine tool for measuring code performance.&nbsp; I like to >>>>>> make sure there are a few test pins on our boards that can be >>>>>> connected >>>>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>>>> programmers understand how to instrument code for such measurements, >>>>>> unfortunately. >>>>> >>>>> Raise a port pin at the start of the routine, and drop it at the end. >>>>> Maybe invert it a couple of times, at interesting points. >>>> >>>> And how do you know that you are raising it at the /real/ start of >>>> the routine, and dropping it at the /real/ end of the routine?&nbsp; I've >>>> seen people write code like : >>>> >>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>> >>>> without realising that the compiler (and processor, for more >>>> advanced cpus) can re-order a lot of that and make the timing >>>> seriously unrealistic. >>> >>> All the embedded stuff I recall doing in C/C++ defines the various >>> port registers as volatile, so the compiler can't play games like that. >>> >>> How would you ever make embedded code work if the compiler could >>> randomly optimize away or reorder port accesses?&nbsp; You could never >>> even poll a hardware flag. >> >> I await David Brown's expert comment, but from >> https://en.cppreference.com/w/c/language/volatile >> >> "This means that within a single thread of execution, a volatile >> access cannot be optimized out or reordered relative to another >> visible side effect that is separated by a sequence point from the >> volatile access." > > The end of a statement is a sequence point. >
The relevant of this is if you have: volatile int v1, v2; then you are not guaranteed anything about the number or order of reads if you write: x = v1 + v2 + v2 + v1; Each of "v1" and "v2" will be read, but they can be read once or twice and in any order, since there is no sequence point between their accesses.
On 05/06/2020 11:07, Tom Gardner wrote:
> On 05/06/20 09:45, Phil Hobbs wrote: >> On 2020-06-05 04:05, David Brown wrote: >>> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>>> <david.brown@hesbynett.no> wrote: >>>> >>>> >>>>>> >>>>>> That's what I have to do, use an oscilloscope to show programmers >>>>>> what >>>>>> their code does. You can often relate the pulse widths to paths >>>>>> through the code. >>>>>> >>>>> >>>>> A scope can be a fine tool for measuring code performance.&nbsp; I like to >>>>> make sure there are a few test pins on our boards that can be >>>>> connected >>>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>>> programmers understand how to instrument code for such measurements, >>>>> unfortunately. >>>> >>>> Raise a port pin at the start of the routine, and drop it at the end. >>>> Maybe invert it a couple of times, at interesting points. >>> >>> And how do you know that you are raising it at the /real/ start of >>> the routine, and dropping it at the /real/ end of the routine?&nbsp; I've >>> seen people write code like : >>> >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>> >>> without realising that the compiler (and processor, for more advanced >>> cpus) can re-order a lot of that and make the timing seriously >>> unrealistic. >> >> All the embedded stuff I recall doing in C/C++ defines the various >> port registers as volatile, so the compiler can't play games like that. >> >> How would you ever make embedded code work if the compiler could >> randomly optimize away or reorder port accesses?&nbsp; You could never even >> poll a hardware flag. > > I await David Brown's expert comment, but from > https://en.cppreference.com/w/c/language/volatile > > "This means that within a single thread of execution, a volatile access > cannot be optimized out or reordered relative to another visible side > effect that is separated by a sequence point from the volatile access." >
It is the "visible side effect" (or, the C standards term, "observable behaviour") that is key here. "volatile" accesses order with respect to observable behaviour, which includes other volatile accesses. For anything other than observable behaviour, you have no guarantees of ordering at all. Sequence points don't affect that.
> "Note that volatile variables are not suitable for communication between > threads; they do not offer atomicity, synchronization, or memory ordering." > > Note that last caveat, and welcome to the world of modern > aggressive optimisers. I'll refrain from commenting on some > compiler writer's attitudes - see recent discussions in > comp.arch if you are interested in that. > > Having to *fully* understand all those subtle terms is one > of the reasons that being able to read assembler code remains > valuable :(
On 05/06/2020 11:56, Phil Hobbs wrote:
> On 2020-06-05 05:48, Tom Gardner wrote: >> On 05/06/20 10:25, Phil Hobbs wrote: >>> On 2020-06-05 05:07, Tom Gardner wrote: >>>> On 05/06/20 09:45, Phil Hobbs wrote: >>>>> On 2020-06-05 04:05, David Brown wrote: >>>>>> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>>>>>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>>>>>> <david.brown@hesbynett.no> wrote: >>>>>>> >>>>>>> >>>>>>>>> >>>>>>>>> That's what I have to do, use an oscilloscope to show >>>>>>>>> programmers what >>>>>>>>> their code does. You can often relate the pulse widths to paths >>>>>>>>> through the code. >>>>>>>>> >>>>>>>> >>>>>>>> A scope can be a fine tool for measuring code performance.&nbsp; I >>>>>>>> like to >>>>>>>> make sure there are a few test pins on our boards that can be >>>>>>>> connected >>>>>>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>>>>>> programmers understand how to instrument code for such >>>>>>>> measurements, >>>>>>>> unfortunately. >>>>>>> >>>>>>> Raise a port pin at the start of the routine, and drop it at the >>>>>>> end. >>>>>>> Maybe invert it a couple of times, at interesting points. >>>>>> >>>>>> And how do you know that you are raising it at the /real/ start of >>>>>> the routine, and dropping it at the /real/ end of the routine? >>>>>> I've seen people write code like : >>>>>> >>>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >>>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >>>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >>>>>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>>>>> >>>>>> without realising that the compiler (and processor, for more >>>>>> advanced cpus) can re-order a lot of that and make the timing >>>>>> seriously unrealistic. >>>>> >>>>> All the embedded stuff I recall doing in C/C++ defines the various >>>>> port registers as volatile, so the compiler can't play games like >>>>> that. >>>>> >>>>> How would you ever make embedded code work if the compiler could >>>>> randomly optimize away or reorder port accesses?&nbsp; You could never >>>>> even poll a hardware flag. >>>> >>>> I await David Brown's expert comment, but from >>>> https://en.cppreference.com/w/c/language/volatile >>>> >>>> "This means that within a single thread of execution, a volatile >>>> access cannot be optimized out or reordered relative to another >>>> visible side effect that is separated by a sequence point from the >>>> volatile access." >>> >>> The end of a statement is a sequence point. >> >> That helps, provided the code is written in a sane >> /simple/ way. >> >> I'm it is possible to create cases which are >> problematic. I've seen some remarkably bad code >> in my time :( > > Me too, but DB was just blowing smoke at JL with that silly example. >
No. It was a side track, admittedly, but my logic is sound and matches real-world cases. The fact that you don't understand exactly how volatile works shows exactly my point - a lot of programmers /think/ they understand volatile, but get it subtly wrong. (Perhaps when you've read my longer reply, you'll see the point - I did not give many details in my first reply to John.)
Am 04.06.20 um 22:30 schrieb David Brown:

> > A scope can be a fine tool for measuring code performance.&nbsp; I like to > make sure there are a few test pins on our boards that can be connected > to an oscilloscope precisely for measuring critical code.&nbsp; Not all > programmers understand how to instrument code for such measurements, > unfortunately.
The Beaglebone Black has an 1 GHz ARM CPU and two PRUs. These are 200 MHz riscs without cache and interrupts, just some fast ram for data and code. Each PRU has fast access to a dozen pins or so. I could place edges in C with the full resolution of 5 nsec, and also read that way. cheers, Gerhard
On 05/06/20 09:28, Phil Hobbs wrote:
> On 2020-06-05 03:38, Tom Gardner wrote: >> On 05/06/20 02:51, Phil Hobbs wrote: >>> On 2020-06-04 12:42, Tom Gardner wrote: >>>> On 04/06/20 17:22, jlarkin@highlandsniptechnology.com wrote: >>>>> On Thu, 4 Jun 2020 16:10:06 +0100, Tom Gardner >>>>> <spamjunk@blueyonder.co.uk> wrote: >>>>> >>>>>> On 04/06/20 00:59, John Larkin wrote: >>>>>>> On Thu, 4 Jun 2020 00:25:35 +0100, Tom Gardner >>>>>>> <spamjunk@blueyonder.co.uk> wrote: >>>>>>> >>>>>>>> On 03/06/20 21:21, John Larkin wrote: >>>>>>>>> On Wed, 3 Jun 2020 17:33:30 +0100, Tom Gardner >>>>>>>>> <spamjunk@blueyonder.co.uk> wrote: >>>>>>>>>> >>>>>>>>>> The similarities outweigh the differences. >>>>>>>>> >>>>>>>>> The similarities of that statement, six times, are tedious. >>>>>>>> >>>>>>>> Your misapprehensions on this topic are legion >>>>>>>> and repetitive. >>>>>>>> >>>>>>>> >>>>>>>>> Do you design electronics? >>>>>>>> >>>>>>>> I did, for decades. >>>>>>>> >>>>>>>> I also designed and implemented server-side software >>>>>>>> for decades. >>>>>>>> >>>>>>>> Do you implement such software? >>>>>>>> >>>>>>>> (I believe you have said you leave that to others.) >>>>>>> >>>>>>> I wrote two compilers and three pre-emptive RTOSs and maybe a hundred >>>>>>> embedded programs, >>>>>> It is worth pointing out that all of those examples are >>>>>> (almost certainly) very different to general purpose software >>>>>> and, especially, to application servers and the applications >>>>>> that run within them. >>>>> >>>>> What's not general about an RTOS? Thousands of units were sold. >>>> >>>> It is a single specialised program than can be used in >>>> different end equipment. >>>> >>>> There's far more to software and software development >>>> than that. >>>> >>>> >>>> >>>>>> Ditto your organisation and the organisations that write/maintain >>>>>> such codebases. >>>>>> >>>>>> Thus it is unsurprising that you do not understand modern >>>>>> medium/large scale software and software practices. Especially >>>>>> the congruences with medium/large scale hardware. >>>>> >>>>> This is an electronic design group. I deal with the software that >>>>> makes electronic instruments work. My relationship to servers is that >>>>> I have to talk to them, feed them javascript and UDP packets and such. >>>> >>>> No doubt. >>>> >>>> But it confirms that you have no experience of creating >>>> large-scale software systems using modern techniques. >>>> >>>> It is therefore unsurprising that you haven't understood >>>> the congruences with hardware. >>> >>> Congruences between large scale software "using modern techniques" and >>> hardware? Interesting!&nbsp; Since you're obviously expert in both, I'd like to >>> learn more. >> >> More of a jack of all trades and master of none, by choice. >> That has advantages and disadvantages. >> >> >>> What are they, exactly? >> >> That would take a /long/ time to discuss, especially if >> half the concepts are unfamiliar to the audience. >> To take /one/ example >> &nbsp;&nbsp;- how application server frameworks are designed >> &nbsp;&nbsp;&nbsp; and implemented >> &nbsp;&nbsp;- design patterns in the applications' components >> &nbsp;&nbsp;&nbsp; and the way they are composed to form an application, >> &nbsp;&nbsp;- design patterns used to communicate with the outside >> &nbsp;&nbsp;&nbsp; world, >> &nbsp;&nbsp;- antipatterns found in politics, development and design >> >> It is a good topic for a conversation in pubs. >> >> I normally start it by provocatively asking someone to >> distinguish between hardware and software. They normally >> claim it is obvious and come up with a definition. Then >> I introduce them to examples that don't fit their definition. >> Rinse and repeat. > >> Sometimes it can take a long time to realise what the >> proponents of a particular technique are doing, because >> they use unfamiliar terms to describe things that are >> standard in other fields. >> >> Some examples: >> &nbsp;&nbsp;- Jackson's Structured Programming >> &nbsp;&nbsp;- Harel StateCharts >> &nbsp;&nbsp;- many of the more esoteric UML diagrams >> &nbsp;&nbsp;- Hatley and Pirbhai's Strategies for Realtime Systems >> &nbsp;&nbsp;&nbsp; Specification, as successfully used for the Boeing 777 >> &nbsp;&nbsp;- and, obviously, object oriented programming > > So where are the applications to hardware?&nbsp;&nbsp; Even one detailed example would be > interesting.
Not application so much as a lack of difference between hardware and software. Harel StateCharts are a formalisation of finite state machine diagrams, which can obviously be implemented in hardware, software, or a combination of the two. UML diagrams are so legion that it is embarassing. The "Unified" is not far off the superset of diagrams from other methodologies. The the well known ones are class hierarchy diagrams, there are also "swimlane interaction" diagrams, and some that are hierarchical structural compositions of software components - just like hierarchical schematics complete with i/o ports connected by wires. Hatley and Pirbhai is particularly interesting. They have two parallel decomposition hierarchies: specification and implementation. Any of the subcomponents can be specified in any way convenient, e.g. FSMs. Every element in the specification hierarchy must have one or more corresponding entities in the implementation hierarchy, and they can be hardware, software, mechanical etc. While the specification hierarchy is almost completely executable (and there may be tools to do that), the only part that Hatley And Pirbhai automated was a database that tracked the complex mappings between the various parts of the specification and implementation hierarchy components. In aerospace trackability is rather important. In the enterprise arena, many patterns are recognisable, some even with accurately suggestive names such as "filter", "multiplexer", "demultiplexer", "event", "asynchronous X", "synchronous X", "control bus", "message bus", "channel". One of many starting points is https://www.enterpriseintegrationpatterns.com/patterns/messaging/index.html
On 05/06/20 11:12, David Brown wrote:
> On 05/06/2020 10:45, Phil Hobbs wrote: >> On 2020-06-05 04:05, David Brown wrote: >>> On 05/06/2020 04:24, jlarkin@highlandsniptechnology.com wrote: >>>> On Thu, 4 Jun 2020 22:30:14 +0200, David Brown >>>> <david.brown@hesbynett.no> wrote: >>>> >>>> >>>>>> >>>>>> That's what I have to do, use an oscilloscope to show programmers what >>>>>> their code does. You can often relate the pulse widths to paths >>>>>> through the code. >>>>>> >>>>> >>>>> A scope can be a fine tool for measuring code performance.&nbsp; I like to >>>>> make sure there are a few test pins on our boards that can be connected >>>>> to an oscilloscope precisely for measuring critical code.&nbsp; Not all >>>>> programmers understand how to instrument code for such measurements, >>>>> unfortunately. >>>> >>>> Raise a port pin at the start of the routine, and drop it at the end. >>>> Maybe invert it a couple of times, at interesting points. >>> >>> And how do you know that you are raising it at the /real/ start of the >>> routine, and dropping it at the /real/ end of the routine?&nbsp; I've seen people >>> write code like : >>> >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_hi_macro(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = big_calculation(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_pin_lo_macro(); >>> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... >>> >>> without realising that the compiler (and processor, for more advanced cpus) >>> can re-order a lot of that and make the timing seriously unrealistic. >> >> All the embedded stuff I recall doing in C/C++ defines the various port >> registers as volatile, so the compiler can't play games like that. >> > > That's the common misunderstanding. > > "volatile" tells the compiler (but not the processor, write buffers, cache, > memory buffers, or any other hardware) that this particular access can't be > omitted or re-ordered with respect to other volatile accesses or "observable > behaviour". > > But it says /nothing/ about re-ordering with respect to non-observable > behaviour, such as calculations. > > Supposing you want to find out how much time your cpu takes for a multiply > instruction.&nbsp; You might write code like this: > > > // Obviously this would match a real register address > extern volatile unsigned char pin; > > extern unsigned int testresult; > > void testmults(void) { > &nbsp;&nbsp;&nbsp; pin = 1; > > &nbsp;&nbsp;&nbsp; unsigned int t = 1; > &nbsp;&nbsp;&nbsp; for (unsigned int x = 1; x <= 1000; x++) { > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t *= x; > &nbsp;&nbsp;&nbsp; } > > &nbsp;&nbsp;&nbsp; pin = 0; > > &nbsp;&nbsp;&nbsp; testresult = t; > } > > Set the pin high - it's a volatile access, and the compiler can't omit it or > reorder it.&nbsp; Do the calculations.&nbsp; Set the pin low.&nbsp; What can go wrong?&nbsp; You've > been smart enough to "use" the calculation result, so that the compiler doesn't > remove the loop entirely.&nbsp; (Not every programmer would think of that.) > > The compiler is free to re-organise this code in any way it wants, as long as > pin is set to 1 before it is set to 0, and as long as "testresult" gets the > right value in the end. > > It can generate code equivalent to: > > void testmults(void) { > &nbsp;&nbsp;&nbsp; pin = 1; > &nbsp;&nbsp;&nbsp; pin = 0; > > &nbsp;&nbsp;&nbsp; unsigned int t = 1; > &nbsp;&nbsp;&nbsp; for (unsigned int x = 1; x <= 1000; x++) { > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t *= x; > &nbsp;&nbsp;&nbsp; } > > &nbsp;&nbsp;&nbsp; testresult = t; > } > > or > > void testmults(void) { > &nbsp;&nbsp;&nbsp; testresult = 0;&nbsp;&nbsp;&nbsp; // Since that is the answer > > &nbsp;&nbsp;&nbsp; pin = 1; > &nbsp;&nbsp;&nbsp; pin = 0; > > } > > or all sorts of other possibilities. > > The general solution to this is to make sure the calculation depends on an > initial volatile read, and the result is used in a volatile write - that lets > you control where the calculation is done with respect to the volatile pin > control.&nbsp; So you could use: > > static const volatile unsigned int vol_one = 1; > static volatile unsigned int vol_result; > void testmults(void) { > &nbsp;&nbsp;&nbsp; pin = 1; > > &nbsp;&nbsp;&nbsp; unsigned int t = vol_one; > &nbsp;&nbsp;&nbsp; for (unsigned int x = 1; x <= 1000; x++) { > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t *= x; > &nbsp;&nbsp;&nbsp; } > &nbsp;&nbsp;&nbsp; vol_result = t; > > &nbsp;&nbsp;&nbsp; pin = 0; > > &nbsp;&nbsp;&nbsp; testresult = t; > } > > (It is possible to enforce orderings without needing extra memory reads and > writes or instructions using empty gcc inline assembly in careful ways.) > > > Do compilers do this kind of re-arrangement in practice?&nbsp; Yes, they do - but > usually only if there is a good reason for it.&nbsp; I've certainly seen bits of > "measured" code re-arranged with respect to the instrumentation. > > The same problem also occurs with interrupt-disable code.&nbsp; A well-established > example can be seen here: > > <https://www.nongnu.org/avr-libc/user-manual/optimization.html> > > Here, the original author had thought that a "memory barrier" would solve any > such re-arrangement problems - but the example shows it is not the case. > > > And that's all just for the compiler's viewpoint.&nbsp; Hardware can have a big > effect (I'm sure you can imagine) - are you measuring the calculation time, or > the cache miss time, or is the time dependent on the state of the write-back > buffers?&nbsp; Usually the solution there is to do lots of samples so you have an > average timing. > > >> How would you ever make embedded code work if the compiler could randomly >> optimize away or reorder port accesses?&nbsp; You could never even poll a hardware >> flag. >> > > The compiler can't re-order the volatile parts - but it can re-order everything > else.&nbsp; A very common misunderstanding about volatile is that people often think > volatile accesses also order other code and accesses - they do not.&nbsp; (C11/C++11 > atomic accesses can affect the order of other memory accesses, but not the order > of code and calculations.) >
Thanks, David. I knew you would have chapter and verse(!) at your fingertips! Such considerations lead me to believe that most programmers that think they know C, actually don't. It also makes me believe that C has become part of the problem(s) that implementers face. I would prefer it had remained part of the solution.