From 479a1a3d2758cd7535a337eaeb97f477909955da Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 13 Apr 2025 19:48:15 +0200 Subject: [PATCH] feat: I found my old blog It only had 2 posts, but whatever --- Makefile | 3 + README.md | 4 + content/posts/avr-memory-model.md | 110 ++ content/posts/bubble-graph.md | 103 ++ static/example_similarities.csv | 21 + static/malloc-std.png | Bin 0 -> 2787 bytes static/sentence_similarity_graph.gnuplot | 77 + static/sentence_similarity_graph_example.svg | 1562 ++++++++++++++++++ 8 files changed, 1880 insertions(+) create mode 100644 Makefile create mode 100644 content/posts/avr-memory-model.md create mode 100644 content/posts/bubble-graph.md create mode 100755 static/example_similarities.csv create mode 100755 static/malloc-std.png create mode 100755 static/sentence_similarity_graph.gnuplot create mode 100755 static/sentence_similarity_graph_example.svg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ded52d0 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +demo: + docker build -t wip . + docker run --rm -it -p 8080:8080 wip hugo serve --bind 0.0.0.0 --port 8080 diff --git a/README.md b/README.md index 179554c..1182421 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,7 @@ docker run --rm -it -p 8080:8080 wip hugo serve --bind 0.0.0.0 --port 8080 - [ ] how to securely "self-host" using a VPS, portainer and traefik - [ ] how to configure neomutt - [ ] how to securely host a mail server + +### Old sillyblog + - [x] Avr memory model + - [x] similarity graph diff --git a/content/posts/avr-memory-model.md b/content/posts/avr-memory-model.md new file mode 100644 index 0000000..766349e --- /dev/null +++ b/content/posts/avr-memory-model.md @@ -0,0 +1,110 @@ ++++ +date = '2019-03-24' +draft = false +title = 'AVR Memory Model: The Practical Explanation' +tags = ['avr', 'programming', 'memory'] +categories = ['technical'] ++++ + +There is A LOT of people that have already explained this, but I personally don't feel like going through billions of +forum posts, with most of them just dying out somewhere in 2008 with no better answer than "I figured it out, thanks". + +Regardless. BIG shoutout to the amazing people at [AVR Freaks](https://www.avrfreaks.net/). They are really cool. +Seriously. Make a user and ask them about anything, and they'll help you. + +## Disclaimer + +I have only been debugging the memory usage of a specific ATMega chip. I don't know if other AVR chip-types use the +same, but this explanation should be valid for all MCUs that the +[avr-libc](http://www.nongnu.org/avr-libc/user-manual/index.html) package supports. + +I also assume that GNU/Linux is being used on the development computer. + +### Open-Source development tools + +The [avr-gcc](http://www.nongnu.org/avr-libc/user-manual/pages.html) compiler chain is an open source effort to have +C/C++ for AVR Atmel chips. They do provide some rudimentary C++ support, but there's no STL and the `new` and `delete` +keywords are not implemented by default. Even purely virtual functions doesn't work out of the box. + +**But don't fret!** There are ways to implement those features manually. See my [other]() post about getting the build +environment up and running. + +## The Memory Model + +As the avr-libc developers [explain](http://www.nongnu.org/avr-libc/user-manual/malloc.html), there's typically not a +lot of RAM available on most many devices and therefore it's very important to keep track of how much memory you are +using. + +{{< centered image="/malloc-std.png" >}} + +All of these symbols `SP`, `RAMEND`, `__data_start`, `__malloc_heap_start`, etc. Can be modified in the compiler, but +the picture above gives the default layout (for an ATMega128 MCU). It goes without saying, that if you don't have an +external RAM chip, you won't be able to utilize the extra RAM space for that. Otherwise, the memory addresses are pretty +straight forward: `0x0100 => 256` bytes is the start of the memory, `0x10FF => 4351` bytes is the end. If you're +wondering where the RAM ends on your specific MCU, you can usually simply open the spec-sheet of the chip and see the +amount of available memory is in it. +For the [ATMega128](https://www.microchip.com/wwwproducts/en/ATMEGA128) that number is 4096 (`4351 - 256 = 4095` (the +spec-sheet also counts the 0th byte)). + +## The avr-libc Memory Allocators + +Now for the juicy part. whenever you `malloc` something in your program, the allocator first writes a 2-byte *free-list +entry* that tells the system how big your object is. + +Example: + +```cpp +/* ... */ +// Allocate an array of 5 integers +int* my_heap_object = static_cast(malloc(sizeof(int) * 5)); +/* ... */ +``` + +Assuming that the memory has been cleared on chip-startup, the above example ends up with the memory setup looking like +this: (Don't mind the specifc memory addresses. If you're curious, you can try doing this, by attaching `avr-gdb` to a +simulator or On Chip Debugger (OCD)). + +``` +gdb: > x/16xb my_heap_object +0x800100: 0a 00 00 00 00 00 00 00 +0x800108: 00 00 00 00 00 00 00 00 +``` + +The first bytes at address `0x800100` are `0a` and `00`. These bytes are the *free-list* entry and explains how "big" +the object is. When reading this, we have to remember that the model is littleengine-based (meaning that the bytes are +switched), +so we actually have the value of `0x000a`, meaning `10` in decimal. This makes a lot of sense, since we allocated 5 +`int`s, that is of size 2 (16bit integers). + +The memory dump shows 16 bytes in total, so the last 4 bytes displayed in the gdb example are not part of the object. +However, if you look at the Memory Model picture again, you can see that the `__brkval` value points to the biggest +memory address that has not been allocated. In our example, if you check where the `__brkval` points to after our +allocation, we get: + +``` +gdb: > __brkval +$ 268 +``` + +268 in hexadecimal is `0x10c`, and if interpreted as an address we get `0x80010c`, which fits very well with our +example, since it is exactly 12 bytes away from where the free-list entry of `my_heap_object` is located at. + +When `free`-ing the object again, the deallocator looks at the free-list entry at the given address, and wipes the +free-list entry. **This is why you should not free a dangling pointer**. Freeing something that is not really free-list +entry *will* result in undefined behaviour, and I think we all know how bad **that** is. (Even though the AVR +environment is actually very good at handling it. In my experience, it usually just crashes and starts over.) +However, as +[explained](http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#gafb8699abb1f51d920a176e695ff3be8a) in +the avrlibc documentation, freeing the `NULL` value, doesn't do anything. So remember to assign your free'd pointers to +`NULL` afterwards. + +## Wrapping up + +The memory allocators of AVR can be very confusing and if you don't keep your thoughts straight when programming, you +can very easily get yourself into a lot of trouble. Since STL is not available to avr-gcc programmers, we dont have our +glorious smart pointers, so we should implement them ourselves (or use arduino's implementations). That might become a +future blogpost. + +Regardless, I hope this helps the lost souls that are trying to actually use these tools. + +{{< centered image="/6616144.png" >}} diff --git a/content/posts/bubble-graph.md b/content/posts/bubble-graph.md new file mode 100644 index 0000000..afc37a9 --- /dev/null +++ b/content/posts/bubble-graph.md @@ -0,0 +1,103 @@ ++++ +date = '2019-03-13' +draft = false +title = 'Plotting Circular Bubble Graph in LaTeX' +tags = ['latex', 'programming'] +categories = ['technical'] ++++ + +When doing web-intelligence, you might need to visualize what's called inter-sentence similarity in a particular format. +I personally haven't found an official name for these kinds of graphs, so I just simply call them Circular Bubble +Graphs. + +During a university project we needed such a graph in our report, and I got the idea of automatically plotting it +through `gnuplot` and integrating it directly into our report with `gnuplottex`. You can see an example of the outcome +of the script. + +![Sentence similarity bubble graph example](/sentence_similarity_graph_example.svg) + +The script operates on a comma-seperated file (`.csv`). The data should be provided as a matrix of sentences assumed to +be symmetric, with the cells containing a real number from 0 to 1, indicating the similarity between the column and the +row. Because of this symmetric property, half of the matrix is ignored by the script. (It also ignores the diagonal, +since sentence `23` will always have a maximum similarity to sentence `23`. It would also be hard to plot that line) + +The whole script can be seen below, but you can also download it as a file +[here](/sentence_similarity_graph.gnuplot). Make sure to set the `my_dataset` variable to your desired +dataset. Example matrix can be downloaded [here](/example_similarities.csv). + +```bash +# Sentence similarity graph plotter +# uncomment this for manual operation of the dataset plotted +# my_dataset = "./sentence_similarities.csv" # ARG1 +set parametric +set size square + +# Styling +set pointsize 7.5 +set style fill solid 1.0 border rgb 'grey30' +set style line 1 lc rgb 'black' pt 6 lw 0.5 + +# Basically a one-dimensional circular coordinate system +fx(t) = cos(t) +fy(t) = sin(t) +rownum = floor(system("wc -l ".my_dataset."")) +1 +coord(k) = (k/real(rownum))*(2*pi) +fxx(t) = cos(coord(t)) +fyy(t) = sin(coord(t)) + +set trange [0:2*pi-(coord(1.0))] +set sample rownum +set noborder +unset tics +set xrange [-1.2:1.2] +set yrange [-1.2:1.2] +set title "Sentence inter-similarity graph" +set multiplot +refloptimization = 0 +do for [i = 0:rownum-1] { + do for [j = refloptimization:rownum-1] { + if (i != j) { + # Get how many columns there are in the dataset. + arrwidth = real(system("awk 'FNR == ".(i+1)." {print $".(j+1)."}' ".my_dataset."")) + if (arrwidth > 0.0) { + bubblerad = 0.125 + x1 = fxx(i) + y1 = fyy(i) + x2 = fxx(j) + y2 = fyy(j) + + dvx = x2-x1 + dvy = y2-y1 + dvl = sqrt((dvx ** 2) + (dvy ** 2)) + x1 = x1 + (dvx/dvl)*bubblerad + y1 = y1 + (dvy/dvl)*bubblerad + x2 = x2 - (dvx/dvl)*bubblerad + y2 = y2 - (dvy/dvl)*bubblerad + # Overleaf's arrow-width rendering is pretty terrible, + # so we use a color-gradient to determine connection-strength. + if (arrwidth > 0.2) { + col = "#000000" + } else { + if (arrwidth < 0.1) { + col = "#B8B8B8" + } else { + col = "#E4E4E4" + } + } + + set arrow "".i.j."" from x1,y1 to x2,y2 nohead lw 0.5 lc rgb col + #set label "H" at (fxx(j)-fxx(i)),(fyy(j)-fyy(i)) + show arrow "".i.j."" + } + } + } + refloptimization = refloptimization + 1 +} +# Plot the circles +plot '+' u (fx(t)):(fy(t)) w p ls 1 notitle + +# Plot the sentence labels +plot '+' u (fx(t)):(fy(t)):(sprintf("s.%d",$0+1)) with labels notitle +``` + +{{< centered image="/6616144.png" >}} diff --git a/static/example_similarities.csv b/static/example_similarities.csv new file mode 100755 index 0000000..a204488 --- /dev/null +++ b/static/example_similarities.csv @@ -0,0 +1,21 @@ +1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0492 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.2353 0.0000 0.0000 0.2182 +0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 1.0000 0.0000 0.1694 0.0510 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.1186 0.0371 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.1694 0.0000 1.0000 0.2748 0.0286 0.2232 0.2697 0.1424 0.0000 0.0000 0.2443 0.2312 0.0000 0.1602 0.0000 0.0000 0.2273 0.1699 +0.0000 0.0000 0.0000 0.0510 0.0000 0.2748 1.0000 0.0480 0.0627 0.0761 0.0432 0.0000 0.0000 0.2907 0.1857 0.0000 0.0543 0.0000 0.0000 0.0737 0.0517 +0.0492 0.0000 0.0000 0.0000 0.0000 0.0286 0.0480 1.0000 0.0520 0.0000 0.0634 0.0000 0.0739 0.1664 0.1848 0.1117 0.0370 0.2022 0.0739 0.2066 0.1055 +0.0000 0.0000 0.0000 0.0000 0.0000 0.2232 0.0627 0.0520 1.0000 0.0000 0.0000 0.0000 0.0000 0.1581 0.0518 0.0000 0.0000 0.0597 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.2697 0.0761 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 0.2148 0.0595 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.1424 0.0432 0.0634 0.0000 0.0000 1.0000 0.0000 0.0000 0.1091 0.0304 0.0000 0.0000 0.0391 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0739 0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.1010 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.1186 0.0000 0.2443 0.2907 0.1664 0.1581 0.2148 0.1091 0.0000 0.0000 1.0000 0.2803 0.0000 0.1291 0.0000 0.0000 0.2894 0.1543 +0.0000 0.0000 0.0000 0.0371 0.0000 0.2312 0.1857 0.1848 0.0518 0.0595 0.0304 0.0000 0.0000 0.2803 1.0000 0.0000 0.0375 0.0560 0.0000 0.2090 0.0748 +0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.1117 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0830 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.1602 0.0543 0.0370 0.0000 0.0000 0.0000 0.0000 0.0000 0.1291 0.0375 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 +0.2353 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.2022 0.0597 0.0000 0.0391 0.0000 0.1010 0.0000 0.0560 0.0830 0.0000 1.0000 0.0000 0.0000 0.2176 +0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0739 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 0.0000 0.0000 0.2273 0.0737 0.2066 0.0000 0.0000 0.0000 0.0000 0.0000 0.2894 0.2090 0.0000 0.0000 0.0000 0.0000 1.0000 0.0650 +0.2182 0.0000 0.0000 0.0000 0.0000 0.1699 0.0517 0.1055 0.0000 0.0000 0.0000 0.0000 0.0000 0.1543 0.0748 0.0000 0.0000 0.2176 0.0000 0.0650 1.0000 \ No newline at end of file diff --git a/static/malloc-std.png b/static/malloc-std.png new file mode 100755 index 0000000000000000000000000000000000000000..0ef14df92181c886e15614abd7b8cbdfbd133c1d GIT binary patch literal 2787 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 WPwNl)eA;_TL8s9Us2VHZ 0.0) { + bubblerad = 0.125 + x1 = fxx(i) + y1 = fyy(i) + x2 = fxx(j) + y2 = fyy(j) + + dvx = x2-x1 + dvy = y2-y1 + dvl = sqrt((dvx ** 2) + (dvy ** 2)) + x1 = x1 + (dvx/dvl)*bubblerad + y1 = y1 + (dvy/dvl)*bubblerad + x2 = x2 - (dvx/dvl)*bubblerad + y2 = y2 - (dvy/dvl)*bubblerad + # Overleaf's arrow-width rendering is pretty terrible, + # so we use a color-gradient to determine connection-strength. + if (arrwidth > 0.2) { + col = "#000000" + } else { + if (arrwidth < 0.1) { + col = "#B8B8B8" + } else { + col = "#E4E4E4" + } + } + + set arrow "".i.j."" from x1,y1 to x2,y2 nohead lw 0.5 lc rgb col + #set label "H" at (fxx(j)-fxx(i)),(fyy(j)-fyy(i)) + show arrow "".i.j."" + } + } + } + refloptimization = refloptimization + 1 +} +# Plot the circles +plot '+' u (fx(t)):(fy(t)) w p ls 1 notitle + +# Plot the sentence labels +plot '+' u (fx(t)):(fy(t)):(sprintf("s.%d",$0+1)) with labels notitle diff --git a/static/sentence_similarity_graph_example.svg b/static/sentence_similarity_graph_example.svg new file mode 100755 index 0000000..52d5971 --- /dev/null +++ b/static/sentence_similarity_graph_example.svg @@ -0,0 +1,1562 @@ + + +Qt SVG Document +Generated with Qt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sentence inter-similarity graph + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sentence inter-similarity graph + + + + + + + + + + + + + + + + + + + + + + + + + + + +s.1 + + + + + + + + + + + + + + + + + + + + + +s.2 + + + + + + + + + + + + + + + + + + + + + +s.3 + + + + + + + + + + + + + + + + + + + + + +s.4 + + + + + + + + + + + + + + + + + + + + + +s.5 + + + + + + + + + + + + + + + + + + + + + +s.6 + + + + + + + + + + + + + + + + + + + + + +s.7 + + + + + + + + + + + + + + + + + + + + + +s.8 + + + + + + + + + + + + + + + + + + + + + +s.9 + + + + + + + + + + + + + + + + + + + + + +s.10 + + + + + + + + + + + + + + + + + + + + + +s.11 + + + + + + + + + + + + + + + + + + + + + +s.12 + + + + + + + + + + + + + + + + + + + + + +s.13 + + + + + + + + + + + + + + + + + + + + + +s.14 + + + + + + + + + + + + + + + + + + + + + +s.15 + + + + + + + + + + + + + + + + + + + + + +s.16 + + + + + + + + + + + + + + + + + + + + + +s.17 + + + + + + + + + + + + + + + + + + + + + +s.18 + + + + + + + + + + + + + + + + + + + + + +s.19 + + + + + + + + + + + + + + + + + + + + + +s.20 + + + + + + + + + + + + + + + + + + + + + +s.21 + + + + + + + + +