05/07/2021 at 12:42 •
It's been a little while since I've put much of an update in here.
I've spent some time refactoring Lovett to get the overall program flow in a better state. I've adopted a strong redux pattern for handling program state changes. There are three major functional container structs. WindowViewer which contains the program views, the Store, which holds the program's state tree and handles reducers, and the Model Scheduler, which (theoretically) would handle starting up program threads as needed. The lines indicate message busses of the type indicated but the diamonds. Event messages indicate what has occurred in the program and they are routed to the dispatcher which determine what action or actions need to be send to the Store. The store runs the reducer code to produce the latest version of the program State. State messages are then relayed to Views in the Window Viewer and to the Model Scheduler and its model treads (should they need state).
I have also been working on a implementing basic configuration as a static struct. This required tapping into the laxy_static crate to define how the static config could be built up at runtime. The config object is static so it can be read anywhere at anytime without having to pass it along as a value everywhere, which could become a bit onerous. Currently the config object holds two things, the font vector and the color palette.
Moving the font vector to a static config was the tactic I took to address another issue. I wanted to use the font in multiple places, but re-loading multiple copies of a font at a few mb each was eating up ram much faster than I had realized. Moving it to a single instance shared in the program got the ram usage back down to normal.
10/24/2020 at 18:52 •
So after my analysis with perf, It looked like the biggest inefficiency was with the way I was using `rusttype` . The draw function was re-rasterizing each character in my onscreen clock for every clock tick. There are several ways to deal with that, but I didn't want to handle it entirely in more complicated app code. I wanted a way to push that kind of issue down into the framework.
With my initial use of rusttype I was having to rasterize the entire string of chars for the clock every second (ie every time the clock ticked forward by one second). This means that every character before the seconds was being rasterized when for most of the time we only needed to rasterize the last couple of chars in the string.
At first I though I could just break down the string a bit into segments, and each segment would be updated only when that time char was updated.. ie render the hours number only when the hours changed. But as a general method this felt like it was putting too much logic into app side of things, when the framework itself should have a better way to do it.
Enter ab_glyph. One of the authors of rusttype was already working on some code that would help this situation out. While ab_glyph was intended to offload some work to a GPU, it had enough gpu independent code to create a local font cache. This means that I only have to rasterize characters when they differ enough from what's in the cache to require it.
It took a bit of work to follow along with how the system works, but after awhile I got it all up and running. And in the process shaved about 1% of cpu usage off! (Hey 1% is important on a raspberry pi zero)
10/08/2020 at 16:54 •
I was noticing that the CPU usage felt a little high on my Lovett framework for a fairly simple operation. So I took a new rabbit hole plunge. One of the best tools to get detailed performance details on a linux system, is the perf tool. It turns out, however, that the driver for by graphics fb requires a newer kernel than the base raspbian system provided. When installing the driver it automatically installs the latest kernel version. That would be ok, except that the kernel install doesn't come with a paired version of perf. So if you want perf, it looks like the only way is to compile it from scratch.
So I go and download the kernel of the same version, hop over to tools/perf and see what it takes to get it up and running. The make utility is fairly helpful here, letting you know what packages you probably need to install to get it up and running. Unfortunately, I ran into a couple of gotchas.
1) It looks like some code expects a different param type than would normally occur in an arm32 compile. A bit of searching turned up a helpful patch: https://lkml.org/lkml/2020/5/11/1474 ... with that in place all the sources were able to compile.
2) Even though it compiled the util was crashing on me before it could do much. That led down another rabbit hole, But I eventually found an option that worked after taking a general glance at this article here: http://web.eece.maine.edu/~vweaver/projects/perf_events/rasp-pi/paradis_ece599.pdf
3) Equipped with
from that article I was able to generate the first round of data. Up next, though I could not generate a report. I was getting a number of crashes. The first one involved libssl. So I went through and did a bunch of raspbian updates, including installing a different libssl version. That triggered a whole lot more updates. At some point one of those updates appeared to have borked by boot options. So I reinstalled the driver which caused a new kernel version to get installed. That then required I go back and repeat steps 1 and 2 above. This time the report crashed on libunwind. So i rebuilt the perf util with
This finally succeeded and the report was not readable.
The result, I found a couple of places to tweak. Opting for some integer math over floating point. And then finally noticing the area of the code that was causing some object to get reinstantiated with a fairly large cpu penalty. Fingers crossed I'll be able to make a much more efficient font rendering and updating code over the next week.
09/29/2020 at 03:24 •
So as I worked through my code, I thought it might be better to just abstract it out into its own framework for pi based fb devices with input buttons.
So I went through my code and pulled out the things that really could be abstracted out. The result was something I decided to name Lovett.
It needs a lot of work, but I figured why not?
09/12/2020 at 05:26 •
So by this point, I’ve pretty well gone off the deep end, because, well, it’s so much fun.
So I started thinking about what would go on top of the canvas layer, which led to the widget layer, which needed a view, which needed a state store, which needed a mutation system. ...
08/23/2020 at 23:41 •
I just got Font handling up and running! It ended up being a bit of a habit hole, as proper font support required getting alpha blending up and running too, and once i had gone there, I dumped the bmp crate for the image crate, with a much larger capability and easy handling of alpha layers.
I'm using the rusttype library from the redox-os project. It wasn't too hard to to get it working ok, and I can use google fonts to get choose some nice typefaces.
Now that I have the main canvas primitives that I want, I can get to adding some basic gui elements and then move on to a sort of gui - view setup, and get a little mvc style thing going.
08/19/2020 at 13:52 •
Adding the GitHub repo for the code here too.
You can check out my current code here: https://github.com/kcculhwch/silviaPiPID
It's currently pretty rough, and the first project I've ever done with rust, so I'm 100% sure many Rustaceans will cringe at my code. Also unit tests need to happen :).
Some of the code for image rendering to fb is derived from example code provided by, https://github.com/Roysten/rust-framebuffer (under the very permissive license, I'm assuming that's ok), as well as some provided by example code for rusttype https://github.com/redox-os/rusttype
08/17/2020 at 05:06 •
I started off playing around with the buttons and display module. First off I just wanted to make sure the display was working well, then I got to building some code to abstract button handling, finally I’m working on the Canvas and rendering pipeline now.
Code coming soon.