Skip to content

Commit

Permalink
small fixes after discussion with professor
Browse files Browse the repository at this point in the history
  • Loading branch information
Pismice committed Jul 11, 2024
1 parent 2ab5593 commit 3adec08
Show file tree
Hide file tree
Showing 16 changed files with 47 additions and 51 deletions.
33 changes: 9 additions & 24 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
Urgent:
- [*] Implémenter auth
- [*] Finir la plannif
- [ ] MVP

N importe quand:
- [ ] Epoll (ptetre lier ca a BD ?)
- [X] Corriger le feedback web et concu
- [ ] regarder la generation de nombre aleatoires
- [ ] rendre cookies secure Secure; HttpOnly; SameSite=Strict
- [ ] tout relier et mettre Dans mes conclusion mettre des liens vers ma doc
- [ ] Verifier que tous les premieres scripts sont exectuables
- [ ] Un script pour lancer les serveurs se serait pas mal
- [ ] https://zig.news/minosian/deciphering-many-item-types-the-skeleton-19i
- [ ] https://imfing.github.io/hextra/docs/guide/
- [ ] Commenter + de code et expliquer les benchmarks

Fin:
- [ ] sources zotero
- [ ] Changer les titres, les images et les liens
- [ ] Changer les titres, les images et les liens pour joli pdf ou latex
- [ ] corriger fautes orthographe

Peut etre:
- [?] Epoll https://discord.com/channels/605571803288698900/1259840408545136700
- [?] Websocket
- [?] Zig and C TODO Add other languages that can use C code and make a graph with matplotlib
- [?] CICD
- [?] debug, binutils, breakpoints, debugger
- [?] https://imfing.github.io/hextra/docs/guide/

Questions:
- Feedback bien dans l'ensemble ? J avais l impression conclusion un peu maigre. Structure bien aussi psq surtout remarques legeres.
- Moyen que l expert regarde le site plutot que le document PDF pour la doc ?
- Jdois faire quoi en + du rapport ? Une affiche et cest tout ?
- Je peux reprendre tel quel vos modif ? pas de soucis de droit d auteur
- Est ce que je peux encore renvoyer ?

Remarques sur feedback:
- Preemptimve multitasking: "useful" le dernier bout de taf peut etre useful pour moi pareil pour "is short lived" cest pas forcement vrai, ca peut etre une groooose tache
- Kernel threads: "it seem a repetition"
- Async/await: "officials" pour moi cest ok car cest les officiels
- Async/await: "intro to libraries??"
- Pas sur de mon graphe sur les coroutines
- std.Thread: "you cannot conclude much"
- est ce que mon lien pour prouver que allocator pour Wasi est suffisant ?
- stack_size: "standard zig stack" cest bien ca
- conclusion : "leaky ??" ??

- std.http : "exact" ?
- std.http : "TODO peut etre mettre un schema" du coup ?
- zap: cest mieux comment jai decrit taskset ?
- Est ce que cest bien avec l intro quand je clique sur le titre ou faudrait mettre intro en bas et tout les solutions encapsulees ?
4 changes: 0 additions & 4 deletions content/about/_index.org
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,3 @@ This site has been generate with [[https://gohugo.io/][Hugo]]
The themes used are:
- [[https://github.com/imfing/hextra][hextra]]
- [[https://github.com/joksas/hugo-simplecite][hugo-simplecite]]

And all the bibliography is display here:
{{< card link="/docs" title="Documentation" icon="document" >}}

7 changes: 5 additions & 2 deletions content/docs/concurrency/_index.org
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ In preemptive multitasking it is the underlying architecture (not us, but the OS

This method gives the advantage of not having to worry about a thread being starved, since the underlying architecture is going to make sure that everyone gets enough CPU time. As we can see in the 2 graphs for preemptive and cooperative multitasking, the preemptive multitasking might context switch our tasks too much, which can lead to a lot of undersiable overhead.

There is an interesting thing that is happening in this graph, at the end we see that task 1 is only doing a very small job, which cost a context switch for almost no job, but the scheduler does not know that a task remains only a small job until done and can context switch it.
There is an interesting thing that is happening in this graph, at the end we see that task 1 is only doing a very small job, which cost a context switch for almost no useful job, but the scheduler does not know that a task remains only a small job until done and can context switch it.
#+CAPTION: Preemptive multitasking
#+NAME: fig:SED-HR4049
[[/images/premp.svg]]
Expand All @@ -72,7 +72,7 @@ Threads are managed by the OS scheduler which is going to decide when to execute

Parallelism becomes achievable through multithreading (even though its not 100% guaranteed). Threads also offer robust isolation, with each thread possessing its own execution context, stack, and local variables, ensuring task independence and preventing interference.

However, scalability can become a concern when managing numerous threads. The overhead of resource allocation by the operating system kernel for each thread may lead to scalability issues, particularly in high-demand environments. To mitigate this, thread pools are often employed to minimize the overhead of thread creation and destruction, thus optimizing performance and resource utilization.
However, scalability can become a concern when managing numerous threads. The overhead of resource allocation by the operating system kernel for each thread may lead to scalability issues, particularly in high-demand environments. This is the case because creating and destroying threads has a non-negligible cost, which can become a bottleneck when dealing with a large number of tasks.

To avoid this overhead, thread pools are often used, which manage a set of threads that can be reused for multiple tasks. This approach reduces the overhead of creating and destroying threads for each task, making it more efficient and scalable.

Expand All @@ -92,3 +92,6 @@ You might think that threads can do that aswell and spawn a thread each time the
A popular library that is used for asynchronous programming is libuv, the giant behind nodejs.

Under the hood libuv is basically a single threaded [[https://docs.libuv.org/en/v1.x/design.html#the-i-o-loop][event-loop]] which is going to perform all IOs on non-blocking sockets that are polled by pollers like epoll, kqueue, ...

*** Zig solutions
We are now going to explore in the different chapters few different ways to achieve concurrency in Zig. We are going to see the pros and cons of each solution and when to use them.
9 changes: 7 additions & 2 deletions content/docs/concurrency/async_await.org
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
#+weight: 2
#+hugo_cascade_type: docs

*** Officials, not supported anymore async/await
*** Zig async/await language feature

{{< callout type="warning" >}}
This feature is not supported anymore since 0.11.0.
{{< /callout >}}

This method uses suspensible stackless coroutines, this solution does not necessarly mean that you are going to have multiple threads or parallelism.

We are not going to dive deeper into this solution because it has been deprecated since 0.11 and is not coming back soon.
Expand Down Expand Up @@ -46,7 +51,7 @@ Here is an exemple in JavaScript where you have to have an =async= main function

Zig solves this problem by not needing to put an =async= keyworkd when our function is asynchronous, instead the compiler can know at compile time if a function is async or not if it contains an =await= keyword.

In Zig 2 exact same codes can behave in a blocking or non-blocking way depending only on this simple declaration:
In Zig, the exact same code can behave in a blocking or non-blocking way depending only on this simple declaration:
#+begin_src zig
pub const io_mode = .evented;
#+end_src
Expand Down
9 changes: 7 additions & 2 deletions content/docs/concurrency/std.Thread.org
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,11 @@ If we run this code with hyperfine (100 runs) once while linking libc (using pth
- LinuxThreadImpl = 276.7s ms += 33.9 ms
- C pthreads = 272.7 ms += 34.0 ms

I tried having 100'000 threads instead of 10'000 but I ran out of memory.
#+CAPTION: Threads benchmark
#+NAME: fig:SED-HR4049
[[/HEIG_ZIG/images/threads_impl.png]]

I tried having 100'000 threads instead of 10'000 in order to get a bigger N but I ran out of memory.

Those test have been run multiple times on different days and the results can vary a bit, but all the implementations can beat each others from time to time, since it is heavily dependent on the OS scheduler and not the thread implementations themselves.

Expand Down Expand Up @@ -320,6 +324,7 @@ However, configuring the stack size is going to be used for every implementation
#+end_src
So if you need to modify it in order to store more local variables, pass more arguments, ... in order to avoid a stack overflow.
Don't put that value too hight either, because you might not have enough space to create a lot of threads after that.
Note that there are currently [[https://github.com/ziglang/zig/issues/157][talks]] about making the stack size known at compilation time and make it only uses what is needs, making the stack size very small compared to that default.

If you want to fine grained your thread further (eg. thread priority) you might need to use the C pthread library, which allow for a ton of possiblites of tuning. Note that when using **std.Thread** you are going to have almost everything set to the default of your implementation. For exemple the only thing that is tuned when using the **PosixThreadImpl** is the guard size.

Expand All @@ -342,7 +347,7 @@ Which corresponds to
**** Conclusion
Zig threads are really useful since they have a very user-friendly abstraction with not a lot of functionalites that are almost never used anyway. This abstraction is also very useful for what we saw earlier, you don't have to worry about the target system, Zig is going to choose the right implementation for you.

But this leaky abstraction comes at a cost, you can not fine-tune your threads as much as you would like to.
But this [[https://en.wikipedia.org/wiki/Leaky_abstraction][leaky abstraction]] comes at a cost, you can not fine-tune your threads as much as you would like to.

If you need specific thread functionalities, like the ones we talked about, you can still do that in Zig by wrapping the C pthread library for exemple or directly use the OS native threads you want.

Expand Down
3 changes: 0 additions & 3 deletions content/docs/project-1/api-design.org
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ The client is going to interact with the game by sendin HTTP requests to the ser

Here is a list of all the possible HTTP requests a player can do.

TODO j hesite si je suis les standards ou si je fais comme je le sens



GET /villages/{id}
Ca renvoie aussi les infos des buildings ?
Expand Down
2 changes: 1 addition & 1 deletion content/docs/project-1/auth.org
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ To do that I am going make my own implementation. I will ask the user its =usern
Three different endpoints will be at disposal.

*** POST /auth/register
Will take the =username= and =password= as parameters. The server will then receive the request, verify that the =username= does not exist already, hash the =password= and store both in a new player entry. It will also generate a random =token= that will also be stored in the database and will act as a session token to authentificate the future requests of the user without asking its password and username again. The session token will be stored as a cookie. Only one session token will be allowed per user. This session token will be sent back to the user as a cookie if the operation is successful.
Will take the =username= and =password= as parameters. The server will then receive the request, hash the =password= and store it with the =username= in a new player entry. It will also generate a random =session_id= that will also be stored in the database and will act as a session token to authentificate the future requests of the user without asking its password and username again. The session token will be stored as a cookie. Only one session token will be allowed per user. This session token will be sent back to the user as a cookie if the operation is successful.

*** POST /auth/login
If the user lost his cookie or connect on a new device, he will provide its =username= and =password=. The server will then check if the hash of the password correspond to the one stored in the database and if it is the case replace in the database the old session token by a new one. The new session token will be sent back to the user as a cookie if the operation is successful.
Expand Down
6 changes: 6 additions & 0 deletions content/docs/project-1/conclusion.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#+title: Conclusion
#+weight: 100
#+hugo_cascade_type: docs
#+math: true

The [[https://github.com/Pismice/Zig-Conquest][repository of the project]] is available on GitHub and open-source for now, might not be in the future for security reasons.
14 changes: 6 additions & 8 deletions content/docs/web/std-http.org
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,24 @@ A very basic implementation that simply sends a string over HTTP to the client.
Since the implementation is blocking and said to be not performant, I tried by myself to make the standard library server as performant as possible by multi-threading it.

In order to maximise the performances I tweak 2 main parameters:
- The number of threads
- What job should be given to the thread
- The number of threads.
- What job should be given to the thread.

For the number of threads it is going to be heavily dependant on your system, notably how many cores you have at disposal and how much tasks your CPU is handling aside from the server.

As a reminder you can use this Zig code to get the number of cores
As a reminder you can use this Zig code to get the number of cores.
#+begin_src zig
std.Thread.getCpuCount()
#+end_src

Or get the needed information from the command line
Or get the needed information from the command line.
#+begin_src shell
lscpu
#+end_src

I then developed to 7 different implementations:
- The implementation from the exact code above
- 2 monothreaded implementations, one with the accept in the main thread and the other with the accept in the spawned thread
- The implementation from the code above.
- 2 monothreaded implementations, one with the accept in the main thread and the other with the accept in the spawned thread.
- 4 multi-threaded implementations, 2 with the accept in the main thread and the other 2 with the accept in the spawned thread with different allocated number of threads.

All the variations except the first one are based on this one code, I just comment/uncomment a few lines to change the implementation.
Expand Down Expand Up @@ -195,8 +195,6 @@ The first main conclusion we can take from this benchmark is that the std.http.S

The second conclusion is that it could be slightly better to open a few threads, 6 or 12 in our case and have all of those threads waiting on the =server.accept()= instead of having only the main thread waiting and then dispatching to a newly spawned thread.

TODO Peut etre mettre un schema qui expliquerait mieux ca, mais je pense que c'est assez clair comme ca.

Note that in real world situations the multi-threaded versions are going to be even performant compared to the monothreaded ones, because all the work like accessing a database and treating the request is going to be done inside the spawned threads and not in the main thread.

*** Conclusion
Expand Down
3 changes: 2 additions & 1 deletion content/docs/web/tokamak.org
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ A basic Tokamak application is really is to get up and running really fast.
const tk = @import("tokamak");

pub fn main() !void {
const allocator = std.heap.page_allocator;
_ = try tk.Server.run(allocator, handler, .{ .port = 8080 });
}

fn handler() ![]const u8 {
return "Wow tokamak is so easy!";
}
}
#+end_src

A lot of the work relies on dependency injection to make the work easier. Like here with the =*tk.Request= and the =std.mem.Alloctor= injectors.
Expand Down
6 changes: 3 additions & 3 deletions content/docs/web/zap.org
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ And then it is going to call the following function every time the endpoint is c
#+end_src

**** facil.io
Since Zap is just a wrapper around [[https://facil.io/][facil.io]], they have very similar performances. We can clearly see that with the benchmarks.
Since Zap is just a wrapper around [[https://facil.io/][facil.io]], they have very similar performances. We can clearly see that with the benchmarks. We can also notice that zap seems slightly better than facil.io, but it is not the case in reality both are equivalent this is due to the randomness [[file:../conclusion][explained here]] that can come from benchmarks like this.
Note that I did add a few other web servers in order to get the comparison more meaningful.

#+CAPTION: Transfers per second for different frameworks
#+NAME: fig:SED-HR4049
[[/HEIG_ZIG/images/facilio.png]]
Note that I did add a few other web servers in order to get the comparison more meaningful.

**** Basic example
Getting a very simple Zap server up and running is quite straightforward. Example taken from one of the [[https://github.com/zigzap/zap/blob/master/examples/hello/hello.zig][examples]].
Expand Down Expand Up @@ -197,7 +197,7 @@ The benchmarks compare 2 different metrics:
#+NAME: fig:SED-HR4049
[[/HEIG_ZIG/images/xfer_per_sec_graph.png]]

Those benchmakrs are in my opinion well made because they assure a good thread equity between the different frameworks. By using [[https://man7.org/linux/man-pages/man1/taskset.1.html][tasket] we can set processes affinities which will increase reproductility by reducing the number of context switching and by imporving cache performances. This also assures a better load balancing between the differnt tasks.
Those benchmakrs are in my opinion well made because they assure a good thread equity between the different frameworks. By using [[https://man7.org/linux/man-pages/man1/taskset.1.html][tasket]] we can set processes affinities which will increase reproductility by reducing the number of context switching and by imporving cache performances. This also assures a better load balancing between the differnt tasks. TODO eviter qu 1 enleve les resources a l autre
#+begin_src shell
TSK_SRV="taskset -c 0,1,2,3"
TSK_LOAD="taskset -c 4,5,6,7"
Expand Down
2 changes: 1 addition & 1 deletion content/docs/zig-and-c.org
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ Then simply switch from calling the source file to the header file.
*** How to call a Zig function from C
You can continue your C project without using Clang or GCC but by using Zig with all its toolchain.

In order to have a c file (main.c) as the entry point of your project using the zig build tool you have to modify the following lines to your build.zig file:
In order to have a C file (main.c) as the entry point of your project using the zig build tool you have to modify the following lines to your build.zig file:
#+begin_src zig
const exe = b.addExecutable(.{
.name = "c_project",
Expand Down
Binary file modified static/HEIG_ZIG/images/coroutines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/HEIG_ZIG/images/threads_impl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/images/coroutines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/threads_impl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3adec08

Please sign in to comment.