WITH [MATERIALIZED]
optimisation fence
Background history
PostgreSQL has a sophisticated query planner which usually gets
the right answer. For good reasons, the pgsql project has
resisted providing lots of knobs to control query planning. But
there are a few ways to influence the query planner, for when the
programmer knows more than the planner.
One of these is the use of a WITH common table
expression. In pgsql versions prior to 12, the planner would
first make a plan for the WITH clause; and then, it would make
a plan for the second half, counting the WITH clause's likely
output as a given. So WITH acts as an "optimisation fence".
This was documented in the manual - not entirely clearly, but
a careful reading of the docs reveals this behaviour:
The WITH query will generally be evaluated as written,
without suppression of rows that the parent query might
discard afterwards.
Users (authors of applications which use PostgreSQL) have been
using this technique for a long time.
New behaviour in PostgreSQL 12
In PostgreSQL 12 upstream were able to make the query planner
more sophisticated. In particular, it is now often capable of
looking "into" the WITH common table expression. Much of the time
this will make things better and faster.
But if WITH was being used for its side-effect as an optimisation
fence, this change will break things: queries that ran very quickly
in earlier versions might now run very slowly. Helpfully,
pgsql 12 still has a way to specify an optimisation fence:
specifying WITH ... AS MATERIALIZED in the query.
So far so good.
Upgrade path for existing users of WITH fence
But what about the upgrade path for existing users of the WITH
fence behaviour?
Such users will have to update their queries to add AS MATERIALIZED.
This is a small change. Having to update a query like this
is part of routine software maintenance and not in itself
very objectionable. However, this change cannnot be made
in advance because pgsql versions prior to 12 will reject
the new syntax.
So the users are in a bit of a bind. The old query syntax
can be unuseably slow with the new database and the new syntax
is rejected by the old database. Upgrading both the database
and the application, in lockstep, is a flag day upgrade,
which every good sysadmin will want to avoid.
A solution to this problem
Colin Watson proposed a very simple solution:
make the earlier PostgreSQL versions accept the new MATERIALIZED syntax.
This is correct since the new syntax specifies precisely
the actual behaviour of the old databases. It has no
deleterious effect on any users of older pgsql versions.
It makes it possible to add the new syntax to the
application, before doing the database upgrade, decoupling
the two upgrades.
Colin Watson even provided an implementation of this proposal.
The solution is rejected by upstream
Unfortunately upstream did not accept this idea. You can read
the whole thread
yourself if you like. But in summary, the objections were
(italic indicates literal quotes):
OFFSET 0 trick
One of the responses in the thread mentions OFFSET 0.
As part of writing the queries in the Xen Project CI system, and
preparing for our system upgrade, I had carefully read the relevant
pgsql documentation. This OFFSET 0 trick was new to me.
But, now that I know the answer, it is easy to provide the right
search terms and find, for example, this
answer on stackmumble.
Apparently adding a no-op OFFSET 0 to the subquery
defeats the pgsql 12 query planner's ability to see into the subquery.
I thinkSo in fact there is a syntax for an optimisation fence that is accepted by both earlier and later PostgreSQL versions. It's even recommended by pgsql devs. It's just not documented, and is described by pgsql developers as a "hack". Astonishingly, the fact that it is a "hack" is given as a reason to use it! Well, I have therefore deployed this "hack". No doubt it will stay in our codebase indefinitely. Please don't be like that! I could come up with a lot more examples of other projects that have exhibited similar arrogance. It is becoming a plague! But every example is contentious, and I don't really feel I need to annoy a dozen separate Free Software communities. So I won't make a laundry list of obstructiveness. If you are an upstream software developer, or a distributor of software to users (eg, a distro maintainer), you have a lot of practical power. In theory it is Free Software so your users could just change it themselves. But for a user or downstream, carrying a patch is often an unsustainable amount of work and risk. Most of us have patches we would love to be running, but which we haven't even written because simply running a nonstandard build is too difficult, no matter how technically excellent our delta. As an upstream, it is very easy to get into a mindset of defending your code's existing behaviour, and to turn your project's guidelines into inflexible rules. Constant exposure to users who make silly mistakes, and rudely ask for absurd changes, can lead to core project members feeling embattled. But there is no need for an upstream to feel embattled! You have the vast majority of the power over the software, and over your project communication fora. Use that power consciously, for good. I can't say that arrogance will hurt you in the short term. Users of software with obstructive upstreams do not have many good immediate options. But we do have longer-term choices: we can choose which software to use, and we can choose whether to try to help improve the software we use. After reading Colin's experience, I am less likely to try to help improve the experience of other PostgreSQL users by contributing upstream. It doesn't seem like there would be any point. Indeed, instead of helping the PostgreSQL community I am now using them as an example of bad practice. I'm only half sorry about that.OFFSET 0is the better approach since it's more obviously a hack showing that something weird is going on, and it's unlikely we'll ever change the optimiser behaviour aroundOFFSET 0... wherashopefully CTEs will become inlineable at some pointCTEs became inlineable by default in PostgreSQL 12.
KDE Apps bundle 20.08 has been released recently, and some of the packages are already updated in Debian/unstable. I have updated also all my packages to 20.08 and they are now available for x86_64, i586, and hopefully aarch64 (some issues remaining here still).
With the new release 20.08 I have also switched to versioned app repositories, so you need to update the apt sources directive. The new one is
deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/apps2008/Debian_Unstable/ ./
deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/other-deps/Debian_Unstable/ ./ deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/frameworks/Debian_Unstable/ ./ deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/plasma519/Debian_Unstable/ ./ deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/apps2008/Debian_Unstable/ ./ deb https://download.opensuse.org/repositories/home:/npreining:/debian-kde:/other/Debian_Unstable/ ./
I'm mostly happy with that, except for one or two little details. I'd like to
have the titles displayed in bold, for example, so that they're easier to spot
when I skim through a Markdown file. It seems like a simple thing to ask, so I
hope there can be a simple solution.
The first steps
Let's learn the basics.
In Vim world, the rules to highlight files formats are defined in the directory
/usr/share/vim/vim82/syntax (I bet you'll have to adjust this path depending
on the version of Vim that is installed on your system).
And so, for the Markdown file format, the rules are defined in the file
/usr/share/vim/vim82/syntax/markdown.vim.
The first thing we could do is to have a look at this file, try to make sense
of it, and maybe start to make some modifications.
But wait a moment. You should know that modifying a system file is not a great
idea. First because your changes will be lost as soon as an update kicks in and
the package manager replaces this file by a new version. Second, because you
will quickly forget what files you modified, and what were your modifications,
and if you do that too much, you might experience what is called "maintenance
headache" in the long run.
So instead, maybe you DO NOT modify this file, and instead you copy it in your
personal Vim folder, more precisely in ~/.vim/syntax. Create this directory
if it does not exist:
mkdir -p ~/.vim/syntax
cp /usr/share/vim/vim82/syntax/markdown.vim ~/.vim/syntax
/usr/share/vim/vim82/syntax/, it is a replacement for the
existing syntax files. And so from now on, Vim uses the file
~/.vim/syntax/markdown.vim, and this is where we can make our modifications.
(And by the way, this is explained in the Vim faq-24.12)
And so, it's already nice to know all of that, but wait, there's even better.
There's is another location of interest, and it is ~/.vim/after/syntax. You
can drop syntax files in this directory, and these files are treated as
additions to the existing syntax. So if you only want to make slight
modifications, that's the way to go.
(And by the way, this is explained in the Vim faq-24.11)
So let's forget about a syntax replacement in ~/.vim/syntax/markdown.vim, and
instead let's go for some syntax additions in ~/.vim/after/syntax/markdown.vim.
mkdir -p ~/.vim/after/syntax
touch ~/.vim/after/syntax/markdown.vim
/usr/share/vim/vim82/syntax/markdown.vim:
hi def link markdownH1 htmlH1
hi def link markdownH2 htmlH2
hi def link markdownH3 htmlH3
...
/usr/share/vim/vim82/syntax/html.vim. So let's have a look into
this file:
hi def link htmlH1 Title
hi def link htmlH2 htmlH1
hi def link htmlH3 htmlH2
...
Title defined? For those using the
default color scheme like me, this is defined straight in the Vim source
code, in the file
src/highlight.c.
CENT("Title term=bold ctermfg=DarkMagenta",
"Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta"),
/usr/share/vim/vim82/colors/.
Alright, so how do we override that? We can just define this kind of rules in
our syntax additions file at ~/.vim/after/syntax/markdown.vim:
hi link markdownH1 markdownHxBold
hi link markdownH2 markdownHxBold
hi markdownHxBold term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta cterm=bold
src/highlight.c, is cterm=bold. And that's already enough to achieve the
initial goal, make the titles (ie. H1 and H2) bold. The result can be seen in
the following screenshot:
The rabbit hole
So we could stop right here, and life would be easy and good.
However, with this solution there's still something that is not perfect. We use
the color DarkMagenta as defined in the default color scheme. What I didn't
mention however, is that this is applicable for a light background. If you
have a dark background though, dark magenta won't be easy to read.
Actually, if you look a bit more into src/highlight.c, you will see that the
default color scheme comes in two variants, one for a light background, and one
for a dark background.
And so the definition for Title for a dark background is as follow:
CENT("Title term=bold ctermfg=LightMagenta",
"Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta"),
background option, and so our
syntax file becomes:
hi link markdownH1 markdownHxBold
hi link markdownH2 markdownHxBold
if &background == "light"
hi markdownHxBold term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta cterm=bold
else
hi markdownHxBold term=bold ctermfg=LightMagenta gui=bold guifg=Magenta cterm=bold
endif
&, and so you
get the value of the background option by writing &background. You can
learn this kind of things in the Vim scripting cheatsheet.
And so, it's easy enough, except for one thing: it doesn't work. The headings
always show up in DarkMagenta, even for a dark background.
This is why I called this paragraph "the rabbit hole", by the way.
So... Well after trying a few things, I noticed that in order to make it work,
I would have to reload the syntax files with :syntax on.
At this point, the most likely explanation is that the background option is
not set yet when the syntax files are loaded at startup, hence it needs to be
reloaded manually afterward.
And after muuuuuuch research, I found out that it's actually possible to set a
hook for when an option is modified. Meaning, it's possible to execute a
function when the background option is modified. Quite cool actually.
And so, there it goes in my ~/.vimrc:
" Reload syntax when the background changes
autocmd OptionSet background if exists("g:syntax_on") syntax on endif
autocmd OptionSet backgroundif exists("g:syntax_on")syntax onmarkdown.vim syntax. It
makes H1 and H2 bold, along with their delimiters, and it also colors the
inline code and the code blocks.
" H1 and H2 headings -> bold
hi link markdownH1 markdownHxBold
hi link markdownH2 markdownHxBold
" Heading delimiters (eg '#') and rules (eg '----', '====') -> bold
hi link markdownHeadingDelimiter markdownHxBold
hi link markdownRule markdownHxBold
" Code blocks and inline code -> highlighted
hi link markdownCode htmlH1
" The following test requires this addition to your vimrc:
" autocmd OptionSet background if exists("g:syntax_on") syntax on endif
if &background == "light"
hi markdownHxBold term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta cterm=bold
else
hi markdownHxBold term=bold ctermfg=LightMagenta gui=bold guifg=Magenta cterm=bold
endif
And a dark background:
That's all, that's very little changes compared to the highlighting from the
original syntax file, and now that we understand how it's supposed to be done,
it's not much effort to achieve it.
It's just that finding the workaround to make it work for both light and dark
background took forever, and leaves the usual, unanswered question: bug or
feature?
Today is Debian's 27th anniversary. We recently wrote
about some ideas to celebrate the DebianDay,
you can join the party or organise something yourselves :-)
Today is also an opportunity for you to start or resume your
contributions to Debian. For example, you can scratch your creative itch
and suggest a wallpaper to be part of the artwork for the next release,
have a look at the DebConf20 schedule
and register to participate online (August 23rd to 29th, 2020),
or put a Debian live image in a DVD or USB
and give it to some person near you, who still didn't discover Debian.
Our favorite operating system is the result of all the work we do together.
Thanks to everybody who has contributed in these 27 years, and happy birthday Debian!
ffmpeg -i video.mp4 -i video.eng.srt -map 0:v -map 0:a -c copy -map 1 \
-c:s:0 mov_text -metadata:s:s:0 language="eng" video-out.mp4
ffmpeg -i video.mp4 -i video.deu.srt -i video.eng.srt -map 0:v -map 0:a \
-c:v copy -c:a aac -map 1 -c:s:0 mov_text -metadata:s:s:0 language="deu" \
-map 2 -c:s:1 mov_text -metadata:s:s:1 language="eng" video-out.mp4
ffmpeg -i video.mp4 -vf subtitles=video.eng.srt video-out.mp4
-vf option is no longer enough:
ffmpeg -i video.mp4 -i overlay.jpg -filter:a "volume=10" \
-filter_complex '[0:v][1:v]overlay[outv];[outv]subtitles=video.eng.srt' \
video-out.mp4
Following Antonio Terceiro s post on tips for using ffmpeg for
editing
video,
I will also share a bit of my experience producing my video for my
session in
DebConf20.
I recorded my talk today. As Terceiro mentioned, even though I m used
to speaking in front of my webcam (i.e. for my classes and some
smaller conferences I ve worked on during the COVID lockdown), it does
feel a bit weird to present a live talk to nobody :-
OK, one step back. Why are we doing this? Because our hardworking
friends of the DebConf20 video team recommended so. In order to
minimize connecitvity issues from the variety of speakers throughout
the world, we were requested to pre-record the exposition part of
our talks, send them to the video team (deadline: today
2020-08-16, in case you still owe yours!), and make sure to be present
at the end of the talk for the Q&A session. Of course, for a 45 minute
talk, I prepared a 30 minute presentation, saving time for said Q&A
session.
Anyway, I used the excellent OBS
studiolive video mixing/editing program (of
course, Debian packages are
available. This allowed me
to set up several predefined views (combinations and layouts of the
presentation, webcam, and maybe some other sources) and
professionally and elegantly switch between them on the fly.
I am still a newbie with OBS, but I surely see it becoming a part of
my day to day streaming. Of course, my setup still was obvious (me
looking right every now and then to see or control OBS, as I work on a
dual-monitor setup )
Anyway, the experience was very good, much smoother and faster than
what I usually have to do when editing video. But just as I was
finishing thanking the (future) audience and closing the
recording I had to tell the camera, oh, fuck!
The button labeled Start Recording Had not been pressed. So, did
I just lose 30 minutes of my life, plus a half-decent delivered talk?
No, fortunately not. I had previously been playing with OBS, and
configured some things. The button I did press was Start
Streaming .
So, my talk (swearing included, of course) was dutifully streamed over
to my YouTube channel. It
seems up to five people got a sneak preview as to what will my DebConf
participation be (of course, I ve de-listed the video). I pulled it
with the always-handy
youtube-dl, edited out my
curses using kdenlive, and
pushed it to the DebConf video server.
Oh, make sure you follow the advice for recording
presentations. It
has all the relevant advice, the settings you should use, and much
more welcome information if you are new to this.
So Next week, DebConf20! Be there or be square!
autopkgtest, ci.debian.net and friends. We will provide the latest updates
on autopkgtest, autodep8, debci, ci.debian.net, and its integration with the
Debian testing migration software, britney.
We agreed on a split of the content, each one recorded their part, and I
offered to join them together. The logical chaining of the topics is such that
we can't just concatenate the recordings, so we need to interlace our parts.
So I set out to do a full video editing work. I have done this before, although
in a simpler way, for one of the MiniDebconfs we held in Curitiba. In that
case, it was just cutting the noise at the beginning and the end of the
recording, and adding beginning and finish screens with sponsors logos etc.
The first issue I noticed was that both our recordings had a decent amount of
audio noise. To extract the audio track from the videos, I resorted to
How can I extract audio from video with ffmpeg?
on Stack Overflow:
ffmpeg -i input-video.avi -vn -acodec copy output-audio.aac
I then edited the audio with Audacity. I
passed a noise reduction filter a couple of times, then a compressor filter to
amplify my recording on mine, as Paul's already had a good volume. And those
are my more advanced audio editing skills, which I acquired doing my own
podcast.
I now realized I could have just muted the audio tracks from the original clip
and align the noise-free audio with it, but I ended up creating new video files
with the clean audio. Another member of the Stack Overflow family came to the rescue,
in How to merge audio and video file in ffmpeg. To replace the audio stream, we can do something like this:
ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4
Paul's recording had a 4:3 aspect ratio, while the requested format is 16:9.
This late in the game, there was zero chance I would request him to redo the
recording. So I decided to add those black bars on the side to make it the
right aspect when showing full screen. And yet again the quickest answer I could
find came from the Stack Overflow empire:
ffmpeg: pillarbox 4:3 to 16:9:
ffmpeg -i "input43.mkv" -vf "scale=640x480,setsar=1,pad=854:480:107:0" [etc..]
The final editing was done with pitivi, which is what
I have used before. I'm a very basic user, but I could do what I needed. It
was basically splitting the clips at the right places, inserting the slides as
images and aligning them with the video, and making most our video appear small
in the corner when presenting the slides.
P.S.: all the command lines presented here are examples, basically copied from
the linked Q&As, and have to be adapted to your actual input and output
formats.
The system running planet.gnu.org was upgraded/reinstalled to Debian 10 "buster" 
The Debian Janitor is an automated
system that commits fixes for (minor) issues in Debian packages that can be
fixed by software. It gradually started proposing merges in early
December. The first set of changes sent out ran lintian-brush on sid packages maintained in
Git. This post is part of a series about the progress of the
Janitor.
The bot has been submitting merge requests for about seven
months now. The rollout has happened gradually across the
Debian archive, and the bot is now enabled for all packages
maintained on Salsa, GitLab, GitHub and Launchpad.
There are currently over 1,000 open merge requests, and
close to 3,400 merge requests have been merged so far.
Direct pushes are enabled for a number of large Debian
teams, with about 5,000 direct pushes to date. That covers
about 11,000 lintian tags of varying severities (about 75 different varieties) fixed across Debian.
For more information about the Janitor's lintian-fixes efforts, see the landing page
apt install curl certbot /usr/bin/letsencrypt certonly --standalone -d j.example.com,auth.j.example.com -m you@example.com curl https://download.jitsi.org/jitsi-key.gpg.key gpg --dearmor > /etc/apt/jitsi-keyring.gpg echo "deb [signed-by=/etc/apt/jitsi-keyring.gpg] https://download.jitsi.org stable/" > /etc/apt/sources.list.d/jitsi-stable.list apt-get update apt-get -y install jitsi-meetWhen apt installs jitsi-meet and it s dependencies you get asked many questions for configuring things. Most of it works well. If you get the nginx certificate wrong or don t have the full chain then phone clients will abort connections for no apparent reason, it seems that you need to edit /etc/nginx/sites-enabled/j.example.com.conf to use the following ssl configuration:
ssl_certificate /etc/letsencrypt/live/j.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/j.example.com/privkey.pem;Then you have to edit /etc/prosody/conf.d/j.example.com.cfg.lua to use the following ssl configuration:
key = "/etc/letsencrypt/live/j.example.com/privkey.pem"; certificate = "/etc/letsencrypt/live/j.example.com/fullchain.pem";It seems that you need to have an /etc/hosts entry with the public IP address of your server and the names j.example.com j auth.j.example.com . Jitsi also appears to use the names speakerstats.j.example.com conferenceduration.j.example.com lobby.j.example.com conference.j.example.com conference.j.example.com internal.auth.j.example.com but they aren t required for a basic setup, I guess you could add them to /etc/hosts to avoid the possibility of strange errors due to it not finding an internal host name. There are optional features of Jitsi which require some of these names, but so far I ve only used the basic functionality. Access Control This section describes how to restrict conference creation to authenticated users. The secure-domain document [2] shows how to restrict access, but I ll summarise the basics. Edit /etc/prosody/conf.avail/j.example.com.cfg.lua and use the following line in the main VirtualHost section:
authentication = "internal_hashed"Then add the following section:
VirtualHost "guest.j.example.com"
authentication = "anonymous"
c2s_require_encryption = false
modules_enabled =
"turncredentials";
Edit /etc/jitsi/meet/j.example.com-config.js and add the following line:
anonymousdomain: 'guest.j.example.com',Edit /etc/jitsi/jicofo/sip-communicator.properties and add the following line:
org.jitsi.jicofo.auth.URL=XMPP:j.example.comThen run commands like the following to create new users who can create rooms:
prosodyctl register admin j.example.comThen restart most things (Prosody at least, maybe parts of Jitsi too), I rebooted the VM. Now only the accounts you created on the Prosody server will be able to create new meetings. You should be able to add, delete, and change passwords for users via prosodyctl while it s running once you have set this up. Conclusion Once I gave up on the idea of running Jitsi on the same server as anything else it wasn t particularly difficult to set up. Some bits were a little fiddly and hopefully this post will be a useful resource for people who have trouble understanding the documentation. Generally it s not difficult to install if it is the only thing running on a VM.
Welcome to gambaru.de. Here is my monthly report (+ the first week in August) that covers what I have been doing for Debian. If you re interested in Java, Games and LTS topics, this might be interesting for you.
Debian Games

Recently, I discovered bashtop, yet another fancy top-like utility that s mostly written in bash (it uses some python3-psutil and shells out to other common system utilities). I like its use of high-colour graphics and despite being written in bash, it s not as resource heavy as I would have expected and also quite snappy (even on a raspberry pi). While writing this post, I also discovered that the author of bashtop ported it to Python and that the python version is called bpytop (hmm, doesn t quite have the same ring to it), which is even faster and less resource intensive than the bash version (although I haven t tried that yet, I guess I will soon ).
I set out to package it, but someone beat me to it, but since I m also on the backports team these days, I went ahead and backported it for buster. So if you have backports enabled, you can now install it using apt install bashtop -t buster-backports .
Dylan A ssi, who packaged bashtop in Debian, has already filed an ITP for bpytop, so we ll soon have yet another top-like tool in our collection :-)



$ nmcli con show
NAME UUID TYPE DEVICE
br-59d010130b86 d8672d3d-7cf6-484f-9ef8-e6ec3e73bef7 bridge br-59d010130b86
FRITZ!Box 7411 1ed1cec1-f586-4e75-ba6d-c9f6f4cba6e2 wifi wlp4s0
[...]
Step 2: Request to view the PSK for this network based on the UUID
$ nmcli --show-secrets --fields 802-11-wireless-security.psk con show '1ed1cec1-f586-4e75-ba6d-c9f6f4cba6e2'
802-11-wireless-security.psk: 0815471123420511111
When I did the work described earlier in template
haskell, I also explored generic programming
in Haskell to solve a particular problem. StrIoT is a program generator: it
outputs source code, which may depend upon other modules, which need to be
imported via declarations at the top of the source code files.
The data structure that StrIoT manipulates contains information about what
modules are loaded to resolve the names that have been used in the input code,
so we can walk that structure to automatically derive an import list. The
generic programming tools I used for this are from
Scrap Your Boilerplate
(SYB), a module written to complement
a paper of the same name.
In this code snippet, everything and mkQ are from SYB:
extractNames :: Data a => a -> [Name]
extractNames = everything (++) (\a -> mkQ [] f a)
where f = (:[])
The input must be any type which implements typeclass Data, as must all its
members (and their members etc.): This holds for the Template Haskell Exp
types. The output is a normal list of Names. The utility function has a
more specific type Name -> [Name]. This is all that's needed to walk over
the heterogeneous data structures and do something specific (f) when we
encounter a Name.
Post-processing the Names to get a list of modules is simple
nub . catMaybes . map nameModule . concatMap extractNames
Unfortunately, there's a weird GHC behaviour relating to the module names
for some Prelude functions that makes the above less useful in practice.
For example, the Prelude function words :: String -> [String] can normally
be used without an explicit import (since it's a Prelude function). However,
once round-tripped through a Name, it becomes GHC.OldList.words. Attempting
to import GHC.OldList fails in some contexts, because it's a hidden module or
package. I've been meaning to investigate further and, if necessary, file a GHC
bug about this.
For this reason I've scrapped all the above and gone with a different plan. We
go back to requiring the user to specify their required import list explicitly.
We then walk over the Exp data type prior to code generation and decanonicalize
all the Names. I also use generic programming/SYB to do this:
unQualifyNames :: Exp -> Exp
unQualifyNames = everywhere (\a -> mkT f a)
where f :: Name -> Name
f n = if n == '(.)
then mkName "."
else (mkName . last . splitOn "." . pprint) n
I've had to special-case composition (.) since that code-point is also used
as the delimiter between package, module and function. Otherwise this looks
very similar to the earlier function, except using everywhere and mkT (make
transformation) instead of everything and mkQ (make query).
Picolibc Updates
I thought work on picolibc would slow down at some point, but I keep
finding more things that need work. I spent a few weeks working in
libm and then discovered some important memory allocation bugs in the
last week that needed attention too.
Cleaning up the Picolibc Math Library
Picolibc uses the same math library sources as newlib, which includes
code from a range of sources:
void * nano_calloc(malloc_size_t n, malloc_size_t elem)
ptrdiff_t bytes;
void * mem;
if (__builtin_mul_overflow (n, elem, &bytes))
RERRNO = ENOMEM;
return NULL;
mem = nano_malloc(bytes);
if (mem != NULL) memset(mem, 0, bytes);
return mem;
Note the naming here -- nano_mallocr uses nano_ prefixes in the code,
but then uses #defines to change their names to those expected in the
ABI. (No, I don't understand why either). However, GCC sees the real
names and has some idea of what these functions are supposed to do. In
particular, the pattern:
foo = malloc(n);
if (foo) memset(foo, '\0', n);
is converted into a shorter and semantically equivalent:
foo = calloc(n, 1);
Alas, GCC doesn't take into account that this optimization is occurring
inside of the implementation of calloc.
Another sequence of code looked like this:
chunk->size = foo
nano_free((char *) chunk + CHUNK_OFFSET);
Well, GCC knows that the content of memory passed to free cannot
affect the operation of the application, and so it converted this
into:
nano_free((char *) chunk + CHUNK_OFFSET);
Remember that nano_mallocr stores the size of the chunk just before
the active memory. In this case, nano_mallocr was splitting a large
chunk into two pieces, setting the size of the left-over part and
placing that on the free list. Failing to set that size value left
whatever was there before for the size and usually resulted in the
free list becoming quite corrupted.
Both of these problems can be corrected by compiling the code with a
couple of GCC command-line switches (-fno-builtin-malloc and
-fno-builtin-free).
Reworking Malloc
Having spent this much time reading through the nano_mallocr code, I
decided to just go through it and make it easier for me to read today,
hoping that other people (which includes 'future me') will also find
it a bit easier to follow. I picked a couple of things to focus on:
mem = nano_malloc(new_size);
if (mem)
memcpy(mem, old, MIN(old_size, new_size));
nano_free(old);
return mem;
However, this really performs badly when the application is growing a
buffer while accumulating data. A couple of simple optimizations
occurred to me:
for (element = head; element; element = element->next)
do stuff ...
However, this becomes pretty complicated when 'do stuff' includes
removing something from the list:
prev = NULL;
for (element = head; element; element = element->next)
...
if (found)
break;
...
prev = element
if (prev != NULL)
prev->next = element->next;
else
head = element->next;
An extra variable, and a test to figure out how to re-link the list.
Bob showed me a simpler way, which I'm sure many people are familiar
with:
for (ptr = &head; (element = *ptr); ptr = &(element->next))
...
if (found)
break;
*ptr = element->next;
Insertion is similar, as you would expect:
for (ptr = &head; (element = *ptr); ptr = &(element->next))
if (found)
break;
new_element->next = element;
*ptr = new_element;
In terms of memory operations, it's the same -- each 'next' pointer is
fetched exactly once and the list is re-linked by performing a single
store. In terms of reading the code, once you've seen this pattern,
getting rid of the extra variable and the conditionals around the list
update makes it shorter and less prone to errors.
In the nano_mallocr code, instead of using 'prev = NULL', it actually
used 'prev = free_list', and the test for updating the head was 'prev
== element', which really caught me unawares.
System Parameters
Any malloc implementation needs to know a couple of things about the
system it's running on:
typedef struct
char c;
union
void *p;
double d;
long long ll;
size_t s;
u;
align_t;
#define MALLOC_ALIGN (offsetof(align_t, u))
Because C requires struct fields to be stored in order of
declaration, the 'u' field would have to be after the 'c' field, and
would have to be assigned an offset equal to the largest alignment
necessary for any of its members. Testing on a range of machines
yields the following alignment requirements:
| Architecture | Alignment |
|---|---|
| x86_64 | 8 |
| RISC-V | 8 |
| aarch64 | 8 |
| arm | 8 |
| x86 | 4 |
156. This version includes the following changes:
[ Chris Lamb ]
* Update PPU tests for compatibility with Free Pascal versions 3.2.0 or
greater. (Closes: #968124)
* Emit a debug-level logging message when our ppudump(1) version does not
match file header.
* Add and use an assert_diff helper that loads and compares a fixture output
to avoid a bunch of test boilerplate.
[ Frazer Clews ]
* Apply some pylint suggestions to the codebase.
Next.