Posts
4629
Following
317
Followers
482
Linux kernel hacker and maintainer etc.

OpenPGP: 3AB05486C7752FE1
@dpom @nnethercote I've worked on systems programming for my whole career so take my opinions from that angle. I'm specifically talking about code that would end up to kernel, bootloader, firmware, systems service etc. Do not mean to discriminate :-) I think Rust is great because it provides equal platform to work teams that do different areas of software and still get stuff easily integrated.
0
0
1

@dpom @nnethercote Thanks, was aware of this book!

For async in particular the real mechanics are sort of “hidden” given the frameworks that put them nicely on the plate (such as tokio). For that it makes sense for anyone to see how it is “open-coded” just to not feel unsafe when putting weird keywords to the code.

I was a bit lost with that in particular until I read a chapter from book “Rust of Rustaceans”, which has pretty nice explanation of what it actually is: a polling interface and (usually) a thread pool (i.e. “executor”). All the syntax is semantically just macros with language level syntax to place them.

This is how I open Rust concepts. They are either new functions or code generators in some sense. If the latter I just do the exercise of open coding the generator to see what it results in.

It is quite common theme in new Rust language features that they are just code generators that produce a “normalized” subset of “plain” Rust code. By understanding this it takes a lot of magic away and helps to understand what they actually achieve.

1
0
0
@davesh For sure but yeah right now the only go is to read/write for Poylend projects themselves and place it in appropriate data structures for further use :-) I already have instrument reader but nothing I would publish right now. As soon as I get song structured I spin off a Github repository.
0
0
1

Jarkko Sakkinen

I'm implementing crate for reading (and later on writing) #polyend #tracker projects :-) Not proactively developed until I get my serial tool in shape tho. After I have that I might write a playback engine for the projects and a command-line player. For reverse engineering reverb and delay algorithms I'm going to use Bitwig Grid and then just compare sampled output until I get it right.

The utility would be e.g. to convert Polyend project to #Bitwig or #Ableton project and stuff like that but to do proper conversion you first need to have a playback engine for comparative testing even though those tools do no need to play anything.
1
1
2

Jarkko Sakkinen

Theoretically I wonder how feasible it would be to generate some HDL and software from same Rust code base. Borrow checker and lifetime parameters give already a framework for that purpose so I guess it could be theoretically possible. #rustlang #vhdl #verilog
0
0
1

Jarkko Sakkinen

Cool apparently got first PR to zmodem2 crate. Now I have an open source community, quality replace quantity I hope :-)

0
0
1
Found one promising: https://github.com/smol-rs/polling. So I'll give it a shot.
0
0
0

Jarkko Sakkinen

Edited 1 year ago

There’s a lot of stuff how great Rust is in this or that but not so much on evaluating what is bad Rust code and what is good so I’ll throw my 2 cents more like to get some feedback on that, rather than delivering the official truth :-) I’m happy to withdraw my views, I just throw this given the lack of “grown up” and educated viewpoints on efficient Rust code.

Like e.g. consider e.g. async which addresses the lack of non-blocking I/O in the standard library. It brings essentially a workqueue or thread pool abstraction with syntax sugar for polling and scheduling threads in the pool. Inefficient code is still a problem because thread pool is a limited resource, and keeping it too hot can make code stall just like before the feature. async is pretty much same thing as struct workqueue in kernel and not much else.

Making Rust features boring and uninteresting I guess :-) But it is good to make this sort of mind exercise for language features that are essentially glue code generators.

0
0
0

Jarkko Sakkinen

Edited 1 year ago

E.g. here’s a snippet from my zmodem2 crate:

            for (i, field) in payload.split('\0').enumerate() {
                if i == 0 {
                    state.file_name = String::from_str(field).or(Err(Error::Data))?;
                }
                if i == 1 {
                    if let Some(field) = field.split_ascii_whitespace().next() {
                        state.file_size = u32::from_str(field).or(Err(Error::Data))?;
                    }
                }
            }

In terms of how nice looking Rust code it is, well it is not that nice looking but it is heck a lot more efficient than a one-liner with collect‘s between. If this was std code (actually it uses heapless::String) the only heap allocation would happen in String::from_str but there you actually need heap allocated memory because the string length is not known at compile time.

I think that to go beyond basics of Rust to actual production code you need to step up from nice conventions to sort of requirements based of thinking. If code uses Vec, there should always answer on plate why it requires Vec and nice syntax is not a great answer for that question.

Even with e.g. enterprise Java, when in production, a lot of undestanding of how JVM JIT and GC work is required for efficient production code. A great tool needs educated use to actually get the added value sort of, or then actually something like Go might be a better option from purely productivity standpoint.

1
0
1

If the masking gets in the way (which it rarely actually does because compiler is smart), some corner cases can be sorted by calling convention e.g. std::io::Read::read(self, buf). This happens super rarely in practice.

0
0
0

Jarkko Sakkinen

To make manageable #Rust stacks over time, I’ve ended up to following conclusions on how to make I/O connectors between library crates:

  1. Internal Read, Seek and Write traits that specify an API that is a more constrained versions of std::io counterparts. Here the masking is used for benefit so that all in-crate code depends on exactly to internal traits.
  2. A submodule named std.rs containing std::io implementations and macro shenanigans to use it [1]. This way std can be compiled out if required (e.g. when used with embedded_io).
  3. Optionally outside I/O can be embedded with a tuple or enum value containing a tuple.

This way my own crates are pretty easy to glue to std, embedded_io and other crates providing the I/O backend so this sort of indirection makes a lot of sense. The goal is to have a structure with clean separation of internals and connectors to the outside world (which can or might not include std).

[1]

#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")] 
mod std;

#rustlang

1
0
0
In high performance code or something you might want to run in a shim these things do matter because e.g. one thing you want to optimize in high-availability service is round -trips to kernel, i.e. the number of context switches. Heap allocation is serviced either by reusing already mapped but freed memory or software needs to ask more from kernel in the corner case. More random heap allocations a system has circulating in its internals, the higher risk there is unpredictable latency peaks and such. Depends of course of the scale of the service how much this matter or not.
2
0
1

@dpom use a Vec if you need a Vec because it is a Vec :-) it is not a great choice to make a code cleaner, unless you actually need to dynamically grow it later on. function like collect() cleans up code at the cost of using heap for small useless allocations. Allocating from stack on the other hand is just pointer arithmetic.

If the code that aims to be in par with equivalent C code, then these things are relevant. If the use of Rust is more like integration of available components and frameworks with the aim of not loosing productivity of something like JavaScript or Python, then this whole thing does not probably matter all that much…

1
0
1
@dpom given how tied the standard library is to vec, using collect is sort of encouraged in the API nothing to do with Rust as a language. rust is in binary level pretty much equivalent to C++.
1
0
0
@furan which reminded me that i should get one of http://pcmidi.eu/argus.html some day. would like to build ultimate impulse tracker setup :)
1
0
1
@furan reminds me of gravis ultrasound
1
0
1

Jarkko Sakkinen

In Rust programs one common theme, which is not great for optimizing memory footprint, is the heavy use of collect(). Iterators are a great abstraction exactly for the reason that you can view items as a set without having to brute force deploy them as such in memory. One area where no language paradigm can protect against is the overuse of computing resource.

One good recipe against this e.g. in a commercial setting would be to set a constraint for core components to be no_std compatible and have total artistic freedom in user interfacing parts or e.g. storage backend interfacing part i.e. only in I/O code.

Then early steps are slower but sort of investments instead of debt when memory is considered early on…

There’s little gain with the added complexity of Rust to something like Go if this consideration is not done. Sometimes something like Go could do even a better job because then at least garbage collector considers memory constraints..

#rustlang

2
0
4

Jarkko Sakkinen

Edited 1 year ago
so soon back to terminal client. given the crate i wonder if concurrent zmodem transfer and TTY session could be shared just by routing all traffic not prefixed zdle [zpad] zpad to that session. sounds so simple that i have doubts that it would work but would be easy way have them happening concurrently.

in any case a lot of complexity of serial file transfers come from the fact that clients launch an external program to take care of it. not because the overall experience could not be overallly more user friendly.

after i get my zmodem crate integrated to my serial tool, the target to go beyond that is to look into https://en.wikipedia.org/wiki/SMODEM. there's a pile of stuff that has better taken care of in MS-DOS software (Telemate, Telex, SMODEM etc.) than in the modern day linux stack, i guess i'm a serial port and modem activist :-)
0
0
1

Jarkko Sakkinen

Edited 1 year ago

Preparing for v0.1 of my #zmodem2 crate: https://github.com/jarkkojs/zmodem2/issues/9. It is heapless and has a context structure that takes less than 2 KB of memory. Not sync but sequential because I want for first version to have just correct implementation of the protocol. Works also in no_std environment.

#rustlang

1
0
1

Jarkko Sakkinen

Edited 1 year ago
I'll switch to a repo with overlay for buildroot later on, i.e. similar but heck a lot simpler layout to https://github.com/keystone-enclave/keystone/
0
0
0
Show older