Skip to content

Commit

Permalink
finish ulib/, add iperf
Browse files Browse the repository at this point in the history
  • Loading branch information
coolyjg committed Dec 20, 2023
1 parent 9142767 commit d63a61e
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

- [Hello World!](./chap02/apps/helloworld.md)

- [Iperf](./chap02/apps/iperf.md)
- [Iperf3](./chap02/apps/iperf.md)

- [Sqlite](./chap02/apps/sqlite.md)

Expand Down
60 changes: 59 additions & 1 deletion src/chap02/apps/iperf.md
Original file line number Diff line number Diff line change
@@ -1 +1,59 @@
# Iperf

# Iperf3

[iPerf3](https://github.com/esnet/iperf) is a tool for active measurements of the maximum achievable bandwidth on IP networks.

## Build & run

Build and start the [`iperf3`](https://github.com/esnet/iperf) server on Ruxos:

```bash
# in ruxos root directory
make A=apps/c/iperf BLK=y NET=y ARCH=<arch> run
```

## Benchmark

In another shell, run the `iperf3` client:

* iperf on Ruxos as the receiver:

```bash
# TCP
iperf3 -c 127.0.0.1 -p 5555
# UDP
iperf3 -uc 127.0.0.1 -p 5555 -b <sender_bitrate> -l <buffer_len>
```

You need to set the `<sender_bitrate>` (in bits/sec) to avoid sending packets too fast from the client when use UDP.

* iperf on Ruxos as the sender:

```bash
# TCP
iperf3 -c 127.0.0.1 -p 5555 -R
# UDP
iperf3 -uc 127.0.0.1 -p 5555 -b 0 -l <buffer_len> -R
```

By default, the `<buffer_len>` is 128 KB for TCP and 8 KB for UDP. Larger buffer length may improve the performance. You can change it by the `-l` option of `iperf3`.

Note that if the `<buffer_len>` is greater than `1472` (total packet length is exceeded the MTU of the NIC) when use UDP, packets fragmentation will occur. You should enable fragmentation features in [smoltcp](https://github.com/smoltcp-rs/smoltcp):

```toml
# in ruxos/modules/axnet/Cargo.toml
[dependencies.smoltcp]
git = "https://github.com/rcore-os/smoltcp.git"
rev = "2ade274"
default-features = false
features = [
"alloc", "log", # no std
"medium-ethernet",
"proto-ipv4",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dns",
# "fragmentation-buffer-size-65536", "proto-ipv4-fragmentation",
# "reassembly-buffer-size-65536", "reassembly-buffer-count-32",
# "assembler-max-segment-count-32",
]
```

3 changes: 3 additions & 0 deletions src/chap02/apps/sqlite.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@

# Sqlite


32 changes: 32 additions & 0 deletions src/chap07/ulib/ruxlibc.md
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@

# ruxlibc

Inspired by [relibc](https://github.com/redox-os/relibc) and [nolibc](https://github.com/unikraft/unikraft/tree/staging/lib/nolibc), `ruxlibc` is a C user library implemented by Rust. Its main purposes are:

* **Small and concise**. It only contains some of the most commonly used API implementations in libc, greatly reducing the size of the image file. `ruxlibc` uses Rust `feature` and the characteristics of the unikernel operating system to implement conditional compilation according to the application, so that the generated C user library only contains the modules necessary for the application.

* **Based on Rust to ensure memory safety**. Drawing inspiration from `relibc`, `ruxlibc` uses Rust to ensure memory safety as much as possible from the language level. At the same time, reasonable setting of error types and corresponding processing facilitates debugging by OS developers and application developers.

## Features

The implementation of `ruxlibc` follows musl libc, and uses Rust `feature` to achieve tailoring. The features included are introduced below.

| Feature Name | Feature Description |
| --- | --- |
| smp | Enable SMP (symmetric multiprocessing) support. |
| fp_simd | Enable floating point and SIMD support. |
| irq | Enable interrupt handling support. |
| alloc | Enable dynamic memory allocation. |
| tls | Enable thread-local storage. |
| multitask | Enable multi-threading support. |
| fs | Enable file system support. |
| net | Enable networking support. |
| signal | Enable signal support. |
| fd | Enable file descriptor table. |
| pipe | Enable pipe support. |
| select | Enable synchronous I/O multiplexing ([select]) support. |
| epoll | Enable event polling ([epoll]) support. |
| random-hw | Enable random number generation by hardware instruction. |

## How to use ruxlibc

See [Your App](../../chap03/your_app.md) to use `ruxlibc` for C applications.
52 changes: 52 additions & 0 deletions src/chap07/ulib/ruxmusl.md
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@

# ruxmusl

This chapter introduces how [musl libc](https://www.musl-libc.org/) is integrated to RuxOS. `ruxmusl` is tested by libc-bench.

## From musl libc to syscall

### importance to import musl libc

`musl libc` provides corresponding C APIs to C programs and encapsulates the underlying system call API. At the same time, not all C functions require system calls. A large number of string processing functions do not require system calls. These functions that do not require system calls provide a relatively complete and efficient implementation in `musl libc`.

Therefore, after integrating `musl libc` into RuxOS, the string and other related functions implemented by the original ryxlibc are no longer needed, and more APIs are provided without the need to implement them one by one.

### system call number

System calls are a set of portable APIs defined by the kernel. The system call numbers corresponding to system calls of different architectures may be different. In AARCH64, you can get the A64-defined system calls and their call numbers by looking at `path/to/musl-libc/arch/aarch64/bits/syscall.h.in`.

Comparing the system calls of different architectures, we can find that not only the system call numbers are different, but the types are also different. For example, A64 provides two system calls, `dup` and `dup3`, but not `dup2`. `dup2` is implemented through `dup + fcntl`; but x86_64 provides `dup/dup2/dup3`.

### trigger a synchronization exception

How to enter the kernel system call layer from the libc function? Take the `read()` function as an example.

* `read()` is a function provided by the C standard library and is implemented in `path/to/musl-libc/src/unistd/read.c`. You can see that `syscall_cp(SYS_read, fd, buf, count)` is called. Here, the system call is called through macro, defined in `path/to/musl/arch/aarch64/syscall_arch.h`. You can see that `svc 0` is passed here, and the relevant parameters are stored in `x0~x5`, and the system call number is stored in `x8`, which means that up to 6 parameters are supported.

* `svc 0` will trigger an interrupt and enter the kernel's interrupt exception vector table. It will trigger a synchronization exception, which will be taken over and processed by the kernel.

## System call handling (A64)

### parse parameters

The synchronization exception will enter `handle_sync_exception()` in `modules/ruxhal/src/arch/aarch64/trap.rs` of RuxOS. The exception triggering cause is obtained by parsing the `ESR` exception status register, and the system call parameters and system call number are obtained by reading `x0~x5` and `x8`.Then enter the system call processing function.

The function `handle_syscall()` is added to the `TrapHandler` trait in `modules/ruxhal/src/trap.rs`, and is only available with `MUSL` feature. The implementation is in `ulib/ruxmusl/src/trap.rs`. System call number is parsed here and then distributed to corresponded handling function.

### system call distribution

The distribution process is in `ulib/ruxmusl/src/syscall/mod.rs`, and the system call number is defined in `ulib/ruxmusl/src/syscall/syscall_id.rs`. It is consistent with the standard system call number (A64), but it is not yet complete. The distribution process is matching system call numbers, parsing different numbers of parameters according to the system call number, and then calling the specific system call implementation in [`ruxos-posix-api`](./ruxos-posix-api.md).

## Use ruxmusl

The relevant makefile has been modified to integrate the `MUSL` feature. When compiling a C program, **add `MUSL=y` to compile the application** through `musl libc`.

Some of the features that `ruxmusl` must include have been added to the makefile, and no additional work is required:

* **fp_simd**: Since musl needs to compile all C standard library functions involving `double` types, floating point registers are needed.
* **fd**: Since musl needs to initialize stdin/stdout/stderr in the form of a file, this feature needs to be turned on.
* **tls**: `musl libc` manages tls by itself in the thread, and needs to get things like `pthread_self()` through `tls`, so it needs to be turned on.

RuxOS will automatically pull and compile the musl libc source code. Users must add `ARCH=aarch64` because it is currently only integrated for A64.

The compilation process is similar to the previous ruxlibc. The previous ruxlibc will compile a `.a` file under the `target/` directory, and `musl libc` will also generate a `libc.a` file under the `install/` directory after compilation. Use this `.a` file for linking (already integrated into makefile).

6 changes: 3 additions & 3 deletions src/chap07/ulib/ulib.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

This chapter will cover:

* What ruxlibc is, and how to use ruxlibc
* What [ruxlibc](./ruxlibc.md) is, and how to use ruxlibc

* How musl is integrated and what is ruxmusl
* How musl libc is integrated and what is [ruxmusl](./ruxmusl.md)

* What ruxos-posix-api is, and the difference between ruxos-posix-api and standard posix API
* What [ruxos-posix-api](./ruxos-posix-api.md) is, and the difference between ruxos-posix-api and standard posix API

0 comments on commit d63a61e

Please sign in to comment.