On Sat, 11 Mar 2017 11:13:53 +0000, Tom Gardner <spamjunk@blueyonder.co.uk> wrote:>On 11/03/17 10:23, Paul Rubin wrote: >> Tom Gardner <spamjunk@blueyonder.co.uk> writes: >>> It means such alias analysis is impossible in many (most?) >>> applications. >> >> Global alias analysis, yes, but some local analysis is possible. > >With the emphasis on "some". Significant difficulties >arise with non-primitive data that is shared rather >than copied.> >In the C/C++ /language/, aliasing is a pig resulting in >pessimised code. Typically, unlike other languages, you >have to resort giving extra assertions to the /tools/; those >assertions are the source of quite a few subtle problems.
Language feature selection
Started by ●March 5, 2017
Reply by ●March 11, 20172017-03-11
Reply by ●March 11, 20172017-03-11
Hi George, On 3/11/2017 2:17 AM, George Neuner wrote:> On Fri, 10 Mar 2017 16:49:21 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> On 3/10/2017 11:43 AM, George Neuner wrote: >>> >>> You asked if closures introduced a GC penalty - the answer to which is >>> "not necessarily". Now you are complaining that functions referenced >>> by a closure need to remain available for its entire lifetime. >> >> Yes -- so how does the tool and/or developer ensure it provides the >> intended functionality when required? How do you imbue the tool >> with the "smarts" to be able to analyze these cases (e.g., impose >> a "persistent" implementation) in light of the different ways >> that the developer can opt to use it? > > Dependency (import) analysis shows what is needed - but not when it is > needed. *Safe* dynamic unloading requires some form of GC - but the > form GC takes depends on many factors. > > E.g., using stack-based closures, or in the absence of closures > altogether, it is relatively simple for a compiler to identify uses of > a module and affect OS-based reference counting to control its > residency. This works transitively if all modules obey the same > conventions. > > [This is just like using COM or CORBA interfaces, but the mechanism > would be built into the primary language compiler instead of being a > separate tool. More later.] > > Once you introduce heap-based closures the lifetime of closures > becomes indefinite: it can be *estimated* by a compiler - e.g., using > region analysis - but runtime GC generally is better at noticing > disuse in a timely fashion. Module reference counting by the compiler > is no longer sufficient and must be augmented by runtime GC.This (as with other aspects below) suggests the compiler really needs to see the entire "application" ("system"). And, even then, can be tripped up because it doesn't know what will come and go (dynamic "applet" loading) or when. Add another "applet" and the apple-cart has been toppled and needs to be re-sorted...>> Alternatively, how do you give the developer tools that let *him* >> convey those dependencies to the tool? >> >> Unless you restrict how they can be used, I don't see how you can >> address each possibility... > > It is up to the programmer to structure her modules so that dynamic > (un)loading is most effective. Modules have management overhead, and > many small modules could be worse than fewer, larger ones. > > There is no formulae for figuring out the best structure. There may > be systemic usage patterns which suggest certain structurings, but > such patterns necessarily are usage dependent.I see this as just making coding more "artful" -- contrary to the current trend in language design ("trained monkeys protected from shooting themselves in the foot")>>> A module has not "served its purpose" if its functions may yet be >>> called in the future. That, in general, is undecidable. >>> >>> The GC standard of "reachability" is conservative - GC does not >>> consider whether an object will be used again because it can't know >>> that. A compiler is in a better position to figure out usage, but >>> even there the only way to know for certain is to simulate execution >>> of the program and observe that it terminates without ever again >>> referencing the object in question. >>> [Hint: indefinate loops can't be guaranteed to terminate.] >> >> Exactly. I "avoid" this issue by requiring the developer to >> handle the "resource reclamation". This means he can make a mistake >> and shoot off both feet (so the OS has to know to catch these >> sorts of problems, indirectly). > > If modules are stateless - iow, all state is in the client - then > modules can come and go at the whim of the OS memory manager. Not > necessarily very performant, but always correct.Technically, even stateful modules can be swapped out -- if the state is preserved in the process.> However, stateless modules likely will seem unnatural to many > programmers, who may find them difficult to create even if there is a > language (or other mechanism) that makes them [relatively] easy to > use.I haven't settled on a consistent way of handling this (which is why I am having trouble imagining how a compiler/tool could uniformly enforce it). I look at each instance and think about how it is intended to be used (cuz *I* am using it!) and let that information dictate how I'll implement. What seems natural in some cases would be piss-poor in others.>>>> [If initialize_heap RETURNS "memory manager"s that are then used to >>>> manage each individual heap, then initialize_heap() itself is still >>>> dynamically bound to those objects. If you unload the module >>>> containing it, then the memory manager objects (in this example) that >>>> it created for the callers also disappears.] >>> >>> Not necessarily - it depends on the module structure. >>> E.g., >>> >>> +----------------+ >>> -| heap functions | >>> / +----------------+ >>> / | >>> / v >>> / +-----------------+ >>> <closure> <-- | initialize_heap | >>> +-----------------+ >>> >>> initialize_heap can be in a module separate from other heap control >>> functions. Once the (heap interface) closure is created, the module >>> containing initialize_heap is unneeded and could be unloaded. >> >> That's how I "manually" implement these things. But *I* have to >> keep track of whether the functions are loaded and *where* they >> are loaded. E.g., if I want to migrate something to another >> node, then I need a handle by which the heap functions (and the >> bindings made at "initialization") can be invoked "later". >> >> I just don't see how a compiler can be aware of this sort of thing >> (without PREVENTING me from doing these sorts of things). > > In the simple case it is just a matter of identifying call sites and > tracking which modules are supplying the called function.I do that at runtime -- by letting the OS track handles and handle references.> The main difficulty stems from reachability of code in the face of > indeterminant loops. The compiler pretty much has to assume that any > call made to the module will actually happen. > > The analysis can be simplified if the language has constructs that > guarantee termination even in the face of errors or exceptions: e.g., > Lisp's unwind-protect or Scheme's dynamic-wind. > >> I think a lot of these sorts of things have an underlying assumption that >> they are part of a persistent, single "program unit" so the compiler doesn't >> have to "worry" about lifespan. > > Most compilers assume libraries/modules are always available *because* > that's what they assume. There is no reason that they must assume > this - it's simply easier to do so. > > Consider the ancient overlay compilers ... dynamic module handling is > not really any different [unless you have to consider the bin-packing > aspect of fitting arbitrary load sequences into memory].Yes, but with overlays you have to engineer their partitioning into your solution. The tool didn't do that on your behalf (by analyzing your code and playing slice-and-dice)>>>> Does the language magically enforce this dependence? Or, does the developer >>>> have to be aware of the potential "gotcha"? Or, does something else reference >>>> count, etc.? > > Modular languages handle dependence - they arrange to load "library" > modules in the same way a C program loads a DLL. However, most > systems have no provisions to automatically unload unreferenced > modules. > > E.g., COM and CORBA, when used via IDL, normally hold a reference to > the library until the program ends (secondary references are added and > deleted in the course of using the library). > > With COM (not sure about CORBA) you can step outside the IDL and > explicitly release the initial reference, which - if there are no > other references held by the program - will unlink the library and > remove it from the program's address space. But that doesn't affect > other clients using the library - the COM server won't terminate the > library until all clients have released it.In my case, "no more references" causes the OS to delete the resource ("unreachable") -- whether that is a dynamically created object (e.g., a heap, in this example) or a static one (e.g., a loaded module -- that might find itself RE-loaded any time now) We just think of things in different ways. You think in terms of the compiler's work, I think in terms of the OS/runtime's.
Reply by ●March 11, 20172017-03-11
On 11/03/17 13:19, Walter Banks wrote:> On 2017-03-11 3:59 AM, Tom Gardner wrote: >> On 11/03/17 02:16, Paul Rubin wrote: >>> Tom Gardner <spamjunk@blueyonder.co.uk> writes: >>>>> There are at least 2 compilers which do whole program alias >>>>> analysis. >>>> >>>> How do they do that if the program includes a library for which >>>> the source is not available, and for which the compiler flags are >>>> not known? >>> >>> "Whole program" means the compiler has all of the source code and >>> can munch it all as a single piece. All kinds of added >>> optimizations are then possible. >> >> I thought you would say that. >> >> It means such alias analysis is impossible in many (most?) >> applications. >> > Yes and no. Libraries can still be precompiled and don't need sources > as long as the object format has the information the compiler needs for > its analysis.Very plausible. Does that occur with common tools, or are "specialist" tools required for the entire system being compiled?
Reply by ●March 11, 20172017-03-11
On 3/11/2017 6:46 AM, Walter Banks wrote:> On 2017-03-10 8:14 PM, Paul Rubin wrote: >> Walter Banks <walter@bytecraft.com> writes: >>>> Do you mean C? >>> More like the whole crop of interpreted languages now being used. >> >> Oh ok, but those languages are generally sugared-up re-inventions of >> Lisp, which is even older than C, and which the cogniscenti have >> been using all along ;-). E. W. Dijkstra in his Turing Award lecture >> back in 1972 had already observed: >> >> With a few very basic principles at its foundation, it [LISP] has >> shown a remarkable stability. Besides that, LISP has been the carrier >> for a considerable number of in a sense our most sophisticated >> computer applications. LISP has jokingly been described as "the most >> intelligent way to misuse a computer". I think that description a >> great compliment because it transmits the full flavour of liberation: >> it has assisted a number of our most gifted fellow humans in thinking >> previously impossible thoughts. >> >> By all means give the interpreters a try if you haven't. They make >> programming more productive along several axes, at the cost of some >> hardware resources (cpu and memory) that are generally plentiful >> with today's computers. >> >>> I tend to think of C as something of our generation. >> >> Yes, I was less surprised that good stuff was being done in >> interpreted languages, as that it's now relatively rare for even >> their expert users to have ever used C for anything. > > It is our generation that is obsessed with optimization execution and > data space.Agreed (as I stated elsewhere). But this is only natural given our "upbringing" -- in much the same way that folks who lived through The Great Depression are far less likely to discard items than those who grew up in "times of plenty". And, while hardware has grown cheaper and more capable over the years, you still don't see 32b CPU's in *mice* or debouncing keys in keyboards! Even "fancy" products often leverage external resources to control costs (is there any reason why a TV *can't* do its own speech recognition without farming that task out to some remote server? really??)> Some of the programs I have seen be developed in by these > people tend to be using algorithms that are exchanging our sense of > optimization for application performance. (VR applications for example) > > Related to that we have almost always treated processor resources as a > rare resource and when I changed that mind set on some of the massively > parallel systems I have been working on to processors are just a > resource that needs to be managed like memory in applications I was > suddenly seeing huge leaps in application performance.Agreed. But, that only makes sense in certain contexts. E.g., when I started the design of my current system, I approached it as "dumb motes" connected to a relatively high performance "server". The motes were essentially "I/O extenders" (cuz you can't run thousands of sensor and actuator cables to a single central server). But, I quickly concluded that battery power was unrealistic (do you want to change a hundred batteries in your maintenance cycle??) and "wall warts" too much of an eyesore (a hundred wall warts) as well as impractical from a wiring standpoint (what do you do if you don't have an electric outlet nearby?). And, wireless comms opens up a bundle of security/privacy/reliability issues (at the very least, DoS attacks). A *wired* system avoids all of these issues (power and comms in the same cable). And, once you have the cost (labor) of wiring such a system, saving a few dollars in each node becomes silly -- especially if adding "smarts" means you can REMOVE smarts from that "central server". Distributing the computational tasks requires different notions of "efficiency"; particularly when it comes to managing the developer! The idea of saving a few bytes by packing fields into a word is just nonsense! Or, inlining a function to save a few microseconds at runtime. Add to that the growing trend of opening systems to third-party (or user-based) extension while maintaining a modicum of reliability/security and the old notions of where to spend resources are out the window!
Reply by ●March 11, 20172017-03-11
On 3/10/2017 5:46 PM, Tom Gardner wrote:> On 11/03/17 00:02, Don Y wrote: >> On 3/10/2017 3:42 PM, Walter Banks wrote: >>> Most of my time now is working on both tools and ISA's. There has been >>> some really significant changes in both approaches to compiling for >>> heterogeneous parallel environments and execution environments that have >>> hundreds to thousands of processors in them. >> >> But they are (largely) *static* environments (?). The toolchain doesn't >> have to decide when to bring another processor on-line... or, when it can >> retire a running processor and migrate its workload to some OTHER >> processor, etc. Or, which aspects of an application should be bound >> to specific processors (nearness of related I/Os) and which aspects >> should AVOID particular processors (as they were in insecure locations). > > The more advanced toolchains are doing similar things. > They instrument themselves, determine what the code+data > is *actually* doing at runtime, and optimise the **** out > of that.I don't see how that can happen -- unless you can force all possible uses of the code to occur while that analysis is being undertaken. E.g., if it never sees you hit the brake pedal in your vehicle, it's likely to spend a lot of effort optimizing ignition timing, thinking "brakes" are never/seldom used! :>> That's as opposed to what the compiler can guess they > are doing and where a compiler has to make pessimising > assumptions. > > And such techniques also work with C. For 18 year old > (gulp) results, google for "hplb dynamo". > > And don't forget that some related techniques are implemented > in processor's hardware microarchitecture. > >> [Simulations of my first workload scheduler immediately brought every >> processor online and kept them there! D'uh!] >> >> I've found it "trying" to come up with even a suitable set of criteria >> by which to constrain these choices. E.g., "performance" can be evaluated >> in a variety of ways: throughput, response time, power consumption, >> redundancy, etc. Just coming up with *a* set of criteria is a challenge. >> And, if the user can bias this at run-time, it becomes even more >> challenging! (perhaps userX might be willing to suffer slower response >> times for reduced power consumption?) >> >> [As I get older, I am encountering more applications where The Right Answer >> is really elusive and often not available "at compile time". *Or*, even >> DESIGN TIME! (I'm still at a loss to forumulate a test suite to score >> the performance of the different speech synthesizer implelmentations I've >> created -- let alone their "costs"! sqrt(3) = 1.732 is a "better" answer >> than sqrt(3) = 1.7; but, how do you decide which pronunciation of which >> utterance is "better" -- and, how to weight the performances of the >> limitless number of POSSIBLE uterances to come up with a composite score??)] > > You are correct in presuming that you can't do an > optimal job at compile time, since the information > isn't there - and can't be there.I contend that there are huge classes of "programs" (this is c.a.E, right?) that would fail miserably with such an approach. You're not processing payroll where you can tweek umpteen gazillion iterations of the same loop. Rather, you are at the mercy of the events that transpire in the environment AND some externally sourced notion of relative "values" (neglecting timeliness for the moment).> The bonus of avoiding getting toolchains to make > premature optimisations, is that the same runtime > optimisation techniques also work with different > processors.That would depend on the nature of those optimizations and their potential consequences. Replacing an ADD with a SHIFT (assuming the SHIFT was more economical) isn't going to "color" the result, significantly. And, an application ("program") can behave differently in different execution environments -- optimizations intended to exploit cache would be wasted on a system without cache; applications hosted in a paged memory management environment will benefit from different optimizations than the same application running in a flat/unpaged environment; etc.> There are disadvantages, of course. TANSTAFFL.
Reply by ●March 11, 20172017-03-11
On 3/10/2017 7:46 PM, jim.brakefield@ieee.org wrote:> On Sunday, March 5, 2017 at 8:43:28 PM UTC-6, Don Y wrote: >> A quick/informal/UNSCIENTIFIC poll: >> >> What *single* (non-traditional) language feature do you find most valuable >> in developing code? (and, applicable language if unique to *a* language >> or class of languages) > > A plug for array operators: as in Numpy, IDL/PV~wave, APL and Julia. That > is: array and vector operators baked into the language.You can do this to a certain extent with operator overloading (if you want to support infix syntax). And, of course, just design functions that take specific data types as their arguments.> I've found that > programming at this level yields shorter programs with less debugging: You > windup making your data structures and algorithms use the fewest operators > possible/practical. Writing loops and subscript expressions are mostly > gone! In theory, such renditions of algorithms can be optimized and/or > parallelized by the compiler to a greater extent than for normal code.But, much processing does not revolve around arrays, streams, etc. And, I'd think you'd need to expose much of the inner-workings of those operators for developers to know how/when they can safely be applied. (e.g., applying to a stream is different than an array, /in situ/) This can take some "freedoms" away from the compiler. Arrays, in general, seem to be used too often as kludges. But, coming up with a "generic" mechanism with which to replace them would be difficult. Lists work, in some cases -- as do other "collection" objects.> There is a theoretical vantage point for this style of programming (which I > call "programming in the large" as opposed to "programming in the small"): > the fundamental data structure is, say, an eight dimensional array (possibly > non-contiguous). A scalar is such an array with the extent in each > dimension equal to one. A vector has one dimension with the extent greater > than one, etc. Of course, the array element can be something other than a > scalar (integer, float, etc) such as a record or list or hash table.
Reply by ●March 11, 20172017-03-11
On 11/03/17 20:05, Don Y wrote:> On 3/10/2017 5:46 PM, Tom Gardner wrote: >> On 11/03/17 00:02, Don Y wrote: >>> On 3/10/2017 3:42 PM, Walter Banks wrote: >>>> Most of my time now is working on both tools and ISA's. There has been >>>> some really significant changes in both approaches to compiling for >>>> heterogeneous parallel environments and execution environments that have >>>> hundreds to thousands of processors in them. >>> >>> But they are (largely) *static* environments (?). The toolchain doesn't >>> have to decide when to bring another processor on-line... or, when it can >>> retire a running processor and migrate its workload to some OTHER >>> processor, etc. Or, which aspects of an application should be bound >>> to specific processors (nearness of related I/Os) and which aspects >>> should AVOID particular processors (as they were in insecure locations). >> >> The more advanced toolchains are doing similar things. >> They instrument themselves, determine what the code+data >> is *actually* doing at runtime, and optimise the **** out >> of that. > > I don't see how that can happen -- unless you can force all possible > uses of the code to occur while that analysis is being undertaken.That would be counterproductive, since you want to optimise the common case. (Just like hardware and software caches do). For a surprising example of where an experimental lab investigation became vaguely practical, see http://www.hpl.hp.com/techreports/1999/HPL-1999-77.html http://www.hpl.hp.com/techreports/1999/HPL-1999-78.html> E.g., if it never sees you hit the brake pedal in your vehicle, > it's likely to spend a lot of effort optimizing ignition timing, > thinking "brakes" are never/seldom used! :> > >> That's as opposed to what the compiler can guess they >> are doing and where a compiler has to make pessimising >> assumptions. >> >> And such techniques also work with C. For 18 year old >> (gulp) results, google for "hplb dynamo". >> >> And don't forget that some related techniques are implemented >> in processor's hardware microarchitecture. >> >>> [Simulations of my first workload scheduler immediately brought every >>> processor online and kept them there! D'uh!] >>> >>> I've found it "trying" to come up with even a suitable set of criteria >>> by which to constrain these choices. E.g., "performance" can be evaluated >>> in a variety of ways: throughput, response time, power consumption, >>> redundancy, etc. Just coming up with *a* set of criteria is a challenge. >>> And, if the user can bias this at run-time, it becomes even more >>> challenging! (perhaps userX might be willing to suffer slower response >>> times for reduced power consumption?) >>> >>> [As I get older, I am encountering more applications where The Right Answer >>> is really elusive and often not available "at compile time". *Or*, even >>> DESIGN TIME! (I'm still at a loss to forumulate a test suite to score >>> the performance of the different speech synthesizer implelmentations I've >>> created -- let alone their "costs"! sqrt(3) = 1.732 is a "better" answer >>> than sqrt(3) = 1.7; but, how do you decide which pronunciation of which >>> utterance is "better" -- and, how to weight the performances of the >>> limitless number of POSSIBLE uterances to come up with a composite score??)] >> >> You are correct in presuming that you can't do an >> optimal job at compile time, since the information >> isn't there - and can't be there. > > I contend that there are huge classes of "programs" (this is c.a.E, right?) > that would fail miserably with such an approach. You're not processing > payroll where you can tweek umpteen gazillion iterations of the same loop. > Rather, you are at the mercy of the events that transpire in the environment > AND some externally sourced notion of relative "values" (neglecting timeliness > for the moment).If by "embedded" you mean "tiny", then I agree these techniques are not currently very useful. OTOH I have used them successfully in HA soft realtime telecom call processing systems. Those can reasonably be regarded as "large" embedded systems.>> The bonus of avoiding getting toolchains to make >> premature optimisations, is that the same runtime >> optimisation techniques also work with different >> processors. > > That would depend on the nature of those optimizations and their potential > consequences. Replacing an ADD with a SHIFT (assuming the SHIFT was more > economical) isn't going to "color" the result, significantly. > > And, an application ("program") can behave differently in different > execution environments -- optimizations intended to exploit cache > would be wasted on a system without cache; applications hosted in > a paged memory management environment will benefit from different > optimizations than the same application running in a flat/unpaged > environment; etc.If you have hard realtime embedded systems, all caches are problematic since they are by definition statistical in nature. IIRC the i960 processor had a crude mechanism for freezing its caches, to avoid such issues.>> There are disadvantages, of course. TANSTAFFL.
Reply by ●March 11, 20172017-03-11
On 3/11/2017 2:58 PM, Tom Gardner wrote:> On 11/03/17 20:05, Don Y wrote: >> On 3/10/2017 5:46 PM, Tom Gardner wrote: >>> On 11/03/17 00:02, Don Y wrote: >>>> On 3/10/2017 3:42 PM, Walter Banks wrote: >>>>> Most of my time now is working on both tools and ISA's. There has been >>>>> some really significant changes in both approaches to compiling for >>>>> heterogeneous parallel environments and execution environments that have >>>>> hundreds to thousands of processors in them. >>>> >>>> But they are (largely) *static* environments (?). The toolchain doesn't >>>> have to decide when to bring another processor on-line... or, when it can >>>> retire a running processor and migrate its workload to some OTHER >>>> processor, etc. Or, which aspects of an application should be bound >>>> to specific processors (nearness of related I/Os) and which aspects >>>> should AVOID particular processors (as they were in insecure locations). >>> >>> The more advanced toolchains are doing similar things. >>> They instrument themselves, determine what the code+data >>> is *actually* doing at runtime, and optimise the **** out >>> of that. >> >> I don't see how that can happen -- unless you can force all possible >> uses of the code to occur while that analysis is being undertaken. > > That would be counterproductive, since you want to > optimise the common case. (Just like hardware and > software caches do).But "common" may have little *value*. E.g., I can tolerate my ECU producing a slightly richer burn but can't tolerate my brakes failing to respond in a timely fashion. How many pixels in a multimegapixel image can you afford to corrupt, slightly, before the picture becomes unrecognizable as such? OTOH, if you fail to snap the shutter when commanded...> For a surprising example of where an experimental lab > investigation became vaguely practical, see > http://www.hpl.hp.com/techreports/1999/HPL-1999-77.html > http://www.hpl.hp.com/techreports/1999/HPL-1999-78.html > >> E.g., if it never sees you hit the brake pedal in your vehicle, >> it's likely to spend a lot of effort optimizing ignition timing, >> thinking "brakes" are never/seldom used! :> >> >>> That's as opposed to what the compiler can guess they >>> are doing and where a compiler has to make pessimising >>> assumptions. >>> >>> And such techniques also work with C. For 18 year old >>> (gulp) results, google for "hplb dynamo". >>> >>> And don't forget that some related techniques are implemented >>> in processor's hardware microarchitecture. >>> >>>> [Simulations of my first workload scheduler immediately brought every >>>> processor online and kept them there! D'uh!] >>>> >>>> I've found it "trying" to come up with even a suitable set of criteria >>>> by which to constrain these choices. E.g., "performance" can be evaluated >>>> in a variety of ways: throughput, response time, power consumption, >>>> redundancy, etc. Just coming up with *a* set of criteria is a challenge. >>>> And, if the user can bias this at run-time, it becomes even more >>>> challenging! (perhaps userX might be willing to suffer slower response >>>> times for reduced power consumption?) >>>> >>>> [As I get older, I am encountering more applications where The Right Answer >>>> is really elusive and often not available "at compile time". *Or*, even >>>> DESIGN TIME! (I'm still at a loss to forumulate a test suite to score >>>> the performance of the different speech synthesizer implelmentations I've >>>> created -- let alone their "costs"! sqrt(3) = 1.732 is a "better" answer >>>> than sqrt(3) = 1.7; but, how do you decide which pronunciation of which >>>> utterance is "better" -- and, how to weight the performances of the >>>> limitless number of POSSIBLE uterances to come up with a composite score??)] >>> >>> You are correct in presuming that you can't do an >>> optimal job at compile time, since the information >>> isn't there - and can't be there. >> >> I contend that there are huge classes of "programs" (this is c.a.E, right?) >> that would fail miserably with such an approach. You're not processing >> payroll where you can tweek umpteen gazillion iterations of the same loop. >> Rather, you are at the mercy of the events that transpire in the environment >> AND some externally sourced notion of relative "values" (neglecting timeliness >> for the moment). > > If by "embedded" you mean "tiny", then I agree these > techniques are not currently very useful.No. Embedded means nothing of the sort. Rather, it signifies applications that tend to be driven by events sensed in the environment. Where do I specify the average interarrival time of a particular event? Or, combinations and interactions of events? How do I indicate that this is "typical" behavior vs. worst case? How do you know that the "optimizations" it has chosen make sense in any but THAT case? How do I tune my current system without knowing what one particular set of users will consider "normal use" -- which may differ dramatically from what the next set of users will consider normal? What if their usage patterns change over the course of the product's lifetime? Or, over the course of a single *day*? Should I optimize the video channel? Audio? Speech recognition? Synthesis? The needs of presenting OTA video to a user differ considerably from those of *storing* OTA video for later playback! How do I balance the resources devoted to these tasks -- when either, neither or *both* may be required at any given instant? How does the tool know what resources are available *now* to meet the present workload?> OTOH I have used them successfully in HA soft realtime > telecom call processing systems. Those can reasonably > be regarded as "large" embedded systems.That's akin to a payroll system. Reasonably constant, consistent traffic. How often does it have to manage the fire suppression equipment protecting the switch? Or, deal with folks entering the building via the front doorway? A control system on a warship operates in hugely different conditions based on whether it is sailing "at peace", "on alert" or actively engaged in a firefight. Does the code get rewritten as the warship transitions between these states? Which is the "common case"? Is it defined by number of instructions executed in that state? Or, total elapsed time, there? Or, the *value* of its performance in that state? "We're really efficient at sailing on the open seas but our maneuvering while under fire is really shitty!">>> The bonus of avoiding getting toolchains to make >>> premature optimisations, is that the same runtime >>> optimisation techniques also work with different >>> processors. >> >> That would depend on the nature of those optimizations and their potential >> consequences. Replacing an ADD with a SHIFT (assuming the SHIFT was more >> economical) isn't going to "color" the result, significantly. >> >> And, an application ("program") can behave differently in different >> execution environments -- optimizations intended to exploit cache >> would be wasted on a system without cache; applications hosted in >> a paged memory management environment will benefit from different >> optimizations than the same application running in a flat/unpaged >> environment; etc. > > If you have hard realtime embedded systems, all caches > are problematic since they are by definition statistical > in nature.Doesn't matter if HRT, SRT or NON real-time. The point is the behavior changes. Same source code.> IIRC the i960 processor had a crude mechanism for freezing > its caches, to avoid such issues. > >>> There are disadvantages, of course. TANSTAFFL.
Reply by ●March 11, 20172017-03-11
On Saturday, March 11, 2017 at 7:42:00 AM UTC-6, Niklas Holsti wrote:> On 17-03-11 04:46 , jim.brakefield@ieee.org wrote: > > On Sunday, March 5, 2017 at 8:43:28 PM UTC-6, Don Y wrote: > >> A quick/informal/UNSCIENTIFIC poll: > >> > >> What *single* (non-traditional) language feature do you find most > >> valuable in developing code? (and, applicable language if unique > >> to *a* language or class of languages) > > > > A plug for array operators: as in Numpy, IDL/PV~wave, APL and Julia. > > That is: array and vector operators baked into the language. > > In a language that allows operator overloading, programmers can define > their own array operators. > > > I've found that programming at this level yields shorter programs with > > less debugging: You windup making your data structures and algorithms > > use the fewest operators possible/practical. > > I agree that array operators are useful, but only for relatively simple > cases such as the basic arithmetic operations on arrays. However, taking > it to the APL extreme with complex vector/matrix restructurings (outer > products, lamination, ...) can create code that is hard for others to > understand. > > > There is a theoretical vantage point for this style of programming > > (which I call "programming in the large" as opposed to "programming > > in the small"): > > You may call it that, but I hope you know that most people understand > these large/small terms differently; see > https://en.wikipedia.org/wiki/Programming_in_the_large_and_programming_in_the_small. > > > -- > Niklas Holsti > Tidorum Ltd > niklas holsti tidorum fi > . @ .]> You may call it that, but I hope you know that most people understand ]> these large/small terms differently; see Was not aware of this definition. Tend to consider this type of "programming in the large" as solving an organizational problem and an architectural problem. Another form of programming in the large is characterized by provisioning a complete 64-bit computer: e.g. one with a complete 64-bit address space. ]> I agree that array operators are useful, but only for relatively simple ]> cases such as the basic arithmetic operations on arrays. However, taking ]> it to the APL extreme with complex vector/matrix restructurings (outer ]> products, lamination, ...) can create code that is hard for others to ]> understand. My experience was with scientific programming, so yes this argument has some validity. Am still convinced that it is a useful exercise: Push low level details down into the operators and data structures, consider the various ways of doing this so that the high level operators (that need to be written) emerge. Also consider programming well with "array" operators to require greater experience, know-how and good judgement than doing low level coding. Jim Brakefield
Reply by ●March 11, 20172017-03-11







