-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Concerned about moving parts of modules into Lua #3128
Comments
I raised a similar point in the wrong repo at marcelstoer/docker-nodemcu-build#91. Since this is probably a better place for the conversation, I'll close that one and repeat what I said there here: -----8<----- It would be useful, I think, if we could pick at least in-tree lua_modules directly into a LFS image as part of the firmware bundle. This would lower the friction of jettisoning some "somewhat hairy" C modules in favor of Lua+C hybrids as I've been trying to drive us to (e.g. #2819 and now #3126). However, I understand if there's hesitation to do LFS builds because people might want to add their own modules, and that opens "now I need to let people upload files" which is always a little hair-raising on the web. So... Maybe instead of LFS, landing selected lua_modules in SPIFFS would still be useful. They could still be require-d as is, at the cost of increased memory consumption, and given @TerryE's proposal in #2917, having Lua files in SPIFFS would eventually let us tell people how to compile their LFS images on-module. -----8<----- I know I'm being a little pushy on this, but to repeat myself: we have not demonstrated the ability to write and maintain complicated modules in C. In many cases our modules merely appear to work or work well enough for toys but not for anything robust; memory management errors abound. Fixes for these issues have been very slow in coming (which, I acknowledge, is partially my fault as I would rather not fix them in C). I think finding a way for the builder to add in-tree Lua modules to SPIFFS at least gets us to the point of "it's easy to run" again, at the possible cost of chewing up more RAM while so doing. (Though it would be very useful to measure roughly how much more RAM we're talking. The proposal in #2819 surely can't use that much, he says, naively... and the outline in #3126 suggests leaving the heaviest parts of the data structures in C.) The lack of a satisfactory answer for "easy way to get an image including SPIFFS/LFS" is partially why I haven't been more adamant that #2819 get merged despite its now near feature- and usability-parity with the C |
I also think that using a C/Lua module must not be any more difficult than using a plain C module.
It should be possible to do something similar in the build process.
Maybe step IV above could be simplified by directly retuning just the one module. But that would require to change luac.cross and can wait till later. A separate Implementation of this for Lua 5.1, 5.3 and likely the ESP32 tree would be needed. The modules might then be "auto required" as the C modules are. @TerryE am I completely wrong or is this halfway thinkable. |
Argh. Forgot about ROTables and ROStrings. |
(As an aside that should not detract from the main issue here: AIUI, Lua 5.2 shifted away from "modules register themselves in the global namespace" and I'd kind of like us to do the same. It's already true that we tend to write things like |
I write Lua code on a PC differently that on the ESP. I don't really need to worry about memory use in coding a PC as any app that I write will have 10-100 × less memory needs than I typical app like Word or Firefox. If I am using LFS then the only difference from writing on a PC is that I now need to be careful about data use as I now only have 45Kb (or less if C modules need a bit), but other than that code and If I run Lua from RAM or want to do source loading, then immediately things start to get really complicated as this 40-45Kb now has to be enough for data, code, and any compile overheads. I find this a pain for the simple apps that I cut, and so IMO it is really easy for a new IoT developers to hit these limits and the coding techniques that you need to deploy to mitigate them are really quite advanced. OK, having a decent well written tutorial and FAQs on how to use these techniques would really help, but even then the new developer needs to take the time to read them. So my tl;dr so far is that I broadly agree with @pjsg Philip that in general if we only provide C/Lua hybrid modules then LFS quickly becomes essential. Scaling RAM-base Lua apps is difficult. However, I also agree with @nwf Nathaniel that Lua is simpler language and its memory management feature make it a better vehicle for bulk applications code. The leaner and meaner better for C modules, IMO. But this again tends to make LFS unavoidable. IMO, the major issue with LFS and beginners is that we don't make available a prebuilt Windows command line version of The techniques that I discuss in #3117 have a very limited scope: to allow Lua developers to spin up an FTP or telnet server (or possibly other previsioning service on what is a bare module with just a cloud builder image loaded. Getting some of these running within RAM limits involves some advanced Lua but since this code is canned, the user doesn't need to know all this. @HHHartmann Gregor, I am not sure what your summary if for. It is incorrect in some details. I think that this underlines we could do with a simple explanation of the way of storing Lua code in terms that someone new to IoT could understand, but I feel that this dialogue lies outside this particular issue. @nwf Nathaniel the reason for doing techniques like In general there are all sorts of bear traps in using environments so doing this is really for advanced programmers. I use |
Thanks Philip for raising this issue. I guess you won't be surprised about where I stand on this. I have been advocating for and working towards low entry barriers for the average user all my NodeMCU life. Hence, I share your concerns. So, my fundamental goal is this: never make things more complicated - for the user/developer - than they were. This proposal seems sane from a technical perspective. However, I feel we should first take measures to ensure the build & flash process is as (or more) painless than it is now before moving away from the current paradigm. |
I got a working proof of concept of an LFS which is embedded in the firmware image and can be accesses just like the regular LFS (using node.flashindex2). So there would be an easy way to add ftp and telnet, but also the Lua part of Lua+C modules. My Branch would be https://github.com/HHHartmann/nodemcu-firmware/tree/embedded-lfs |
That's an interesting idea, and is probably simpler than merging LFS images... but. I don't think I like More technically, how do you resolve duplicate entries in the LFS string tables? That was the original reason I suggested merging LFS images "on the fly" on the device. |
@HHHartmann Gregor, on first reading I misunderstood what you are proposing here. That is because when we've previously talked about 2 LFS partitions, this was in the context of on-ESP LFS building where the loader would need an "existing" and "new" LFS partition during the load process. (Incidentally IMO, we need to start to deprecate the Lua 5.1 environment by doing a feature freeze, including this type of development. Any new features such as this should be offered on Lua 5.3 only) What you are now talking about is having 2 live LFS partitions in the runtime:
As you show the runtime overhead is quite small (instead of resolving (new) strings against the RWstrt you now resolve them against the RWstrt then the application ROstrt then the system ROstrt. However I think that we should be discussing the features and functionality here rather than implementation details.
I just feel that making a native Windows |
This all seems very complicated and I don't think it has to be. I would like, and can try to make it so that, our build process...
Armed with that, the basic flow for novice users is a delightfully simple three-stage process almost indistinguishable from the current state of affairs:
The sole complexity here is that we have now occupied the LFS slot with
There. That hardly seems world-endingly bad. There's little need for anything new other than But we should still offer |
Sure this will have to be ported to Lua 5.3 and maybe even ESP32. I saw the Implementation is different, but hope that the general idea will work there too.
Correct.
I see the main benefit in that we then can add Lua modues to the firmware just as we can add c modules while the application developer can have full control over his (own) LFS partition.
Building an LFS image against a firmware sounds like no good idea. An LFS image should work independent of a certain firmware configuration (the required modules have to be in of corse) Maybe the application LFS could be checked for duplicate strings on reflash, just excluding the duplicate ones.
I fully agree. But I think this should be done in Lua, just extending the code in _init.lua. In my _init.lua I also first search SPIFFS to be able to override LFS.
I did not plan to reload the system LFS. There is no way to reload C libraries either.
I agree that it sure would help to have the binary somewhere available.
|
@HHHartmann I am curious for your opinion on my (I think much simpler) proposal, which does not require finding, selecting, or copying files as we land them in the SPIFFS at build time. |
Don't underestimate this issue of (short) strings being interned. On the one hand, I really don't want to introduce the performance hit of doing a strcmp() for string equality, but if we don't then we would need to remove duplicate strings on app LFS load. This is easy to do in the case of the Lua53 image format, but not in the case of the Lua51 format. (Though this would still break a I've already backported a lot of Lua53 improvements into Lua51 -- basically those needed to allow the The alternative is to land them in SPIFFS but I suggest we can also do this at configure time. A single I can't think of any simple magic bullets here. |
@TerryE: I think the solution sketched in #3128 (comment) is a pretty straightforward magic bullet? |
String Interning -- uuuaarrghhh The nub of this issue is that if the sys LFS contains the string "print" say, then "print" will be in the sys ROstrt. If the app LFS refers to the string "print" it has to acquire the sys ROstrt instance on The alternative of doing this deduplication during the This approach really requires the Lua53 image dump format which was designed to support this type of merge (as it happens to facilitate on ESP LFS building, #2917, but it works here as well). If we want Lua 51 to support this as well as Lua53 then I am going to have to backport this Lua53 dump format. |
My suggestion is that we put the implementation of this on the back-burner for a month or so. I would really like to get the next master drop out of the way and my next #3078 work dumped from my working branch into a PR for merge into |
@TerryE: I... believe you read the wrong comment, as the one I pointed you at no longer deals with two LFSes. |
Yup, but this really needs the on-ESP delta load. A lot of common ground 😄 |
Sorry, let me expand on my last comment. @nwf, your scenario delivers a firmware with a single LFS that is pre-populated with any selected Lua modules and examples. If beginners wanted to extend this with their own application modules, then they would need #2917 if they don't have |
I've been thinking more about @HHHartmann's above suggestion of dual LFSs and now think that this is going to be quite workable. We would want to support two variant of boot modes:
The former allow safe loading of a step-up LFS where the last thing the load process does is to toggle the RCR selector for LFS. The latter allows the sys+app concept discussed above. Both modes are a destructive update of the second LFS (otherwise we would need 3 LFS partitions during load which is just getting too hairy). Both require the LFS loader to resolve string duplication across LFSs (in mode 2 only) on the fly during load. On reflection this is straightforward -- that is once we accept that we need to do it. The standard Lua dump(LC) format only contains a single top level function (TLF), and loading it returns a single function data type. If the LC is being loaded into LFS (or in fact we could extend this generally) then it could contain a concatenation of multiple TLFs. In this case the load in essence returns a table of {modname=func} where the modname is based on the sourcefile basename. So long as the LC formats are valid and the total fits in the LFS region then any wildcard of LC files will load into an image. I suggest that I make this the next PR after the error handling one.(*) (*) unless bumped by some priority review changes. |
Still no progress here |
One of the nice things about nodemcu-firmware is that it allows you to build small apps very easily with just esplorer/similar. You build an image with the cloud builder, flash it, and then you can build something.
However, as modules start to be moved into Lua, this means that you can't do this stuff any more as you need to use the LFS to fit all the code into memory. This raises the complexity of the toy development environment significantly.
What could be solutions to this problem? Maybe the cloud builder could build an LFS partition with all (or selected) Lua libraries that are part of nodemcu-firmware, and include this partition in the firmware file that the user then flashes onto their boards.
Comments?
The text was updated successfully, but these errors were encountered: