Skip to content

Commit

Permalink
Merge pull request #1 from Azure-stars/test_ci
Browse files Browse the repository at this point in the history
Run batch tasks and add test CI
  • Loading branch information
Azure-stars authored Aug 2, 2024
2 parents f29a06a + b36ebd1 commit f87e387
Show file tree
Hide file tree
Showing 74 changed files with 273 additions and 44 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,30 @@ jobs:
- run: ./scripts/get_deps.sh
- name: Build for ${{ matrix.arch }}
run: make ARCH=${{ matrix.arch }}

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust-toolchain: [nightly]
arch: [x86_64]
env:
qemu-version: 8.2.0
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: ${{ matrix.rust-toolchain }}
components: rust-src, llvm-tools
- uses: Swatinem/rust-cache@v2
- run: cargo install cargo-binutils
- run: ./scripts/get_deps.sh
- uses: ./.arceos/.github/workflows/actions/setup-musl
with:
arch: ${{ matrix.arch }}
- uses: ./.arceos/.github/workflows/actions/setup-qemu
with:
qemu-version: ${{ env.qemu-version }}
- name: Run tests
run: make test ARCH=${{ matrix.arch }}
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
AX_ROOT ?= $(PWD)/.arceos
AX_TESTCASE ?= nimbos
ARCH ?= x86_64

export AX_TESTCASES_LIST=$(shell cat ./apps/$(AX_TESTCASE)/testcase_list | tr '\n' ',')

all: build

ax_root:
@./scripts/set_ax_root.sh $(AX_ROOT)

user_apps:
@cd ./apps && make ARCH=$(ARCH) build
@make -C ./apps/$(AX_TESTCASE) ARCH=$(ARCH) build

test:
@./scripts/app_test.sh

build run justrun debug disasm clean: ax_root
build run justrun debug disasm: ax_root
@make -C $(AX_ROOT) A=$(PWD) $@

clean: ax_root
@make -C $(AX_ROOT) A=$(PWD) clean
@cargo clean

.PHONY: all ax_root build run justrun debug disasm clean
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ A monolithic kernel based on [ArceOS](https://github.com/arceos-org/arceos).

## Quick Start
```sh
# Clone the base repository
./scripts/get_deps.sh

# Build user applications
cd apps
make ARCH=x86_64 build
cd ..
make user_apps

# Build kernel
make ARCH=x86_64 build
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 15 additions & 0 deletions apps/nimbos/expect_off.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
smp = 1
build_mode = release
log_level = off

Hello world from user mode program!
Hello, world!
Hello, I am process 2.
Back in process 2, iteration 0.
Back in process 2, iteration 1.
Back in process 2, iteration 2.
Back in process 2, iteration 3.
Back in process 2, iteration 4.
yield passed!
into sleep test!
simple_sleep passed!
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
profile = "minimal"
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
channel = "nightly-2022-11-03"
channel = "nightly-2024-05-02"
components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions apps/nimbos/test_cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_one "LOG=off" "expect_off.out"
4 changes: 4 additions & 0 deletions apps/nimbos/testcase_list
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
hello_world
hello_c
yield
sleep_simple
4 changes: 3 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ fn main() {
}

fn link_app_data(arch: &str) -> Result<()> {
let app_path = PathBuf::from("./apps/build/").join(arch);
let testcase = option_env!("AX_TESTCASE").unwrap_or("nimbos");

let app_path = PathBuf::from(format!("apps/{}/build/{}", testcase, arch));
let link_app_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("link_app.S");

if let Ok(dir) = read_dir(&app_path) {
Expand Down
122 changes: 122 additions & 0 deletions scripts/app_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/bin/bash

TIMEOUT=60s
EXIT_STATUS=0
ROOT=$(realpath $(dirname $0))/../

S_PASS=0
S_FAILED=1
S_TIMEOUT=2
S_BUILD_FAILED=3

RED_C="\x1b[31;1m"
GREEN_C="\x1b[32;1m"
YELLOW_C="\x1b[33;1m"
CYAN_C="\x1b[36;1m"
BLOD_C="\x1b[1m"
END_C="\x1b[0m"

if [ -z "$ARCH" ]; then
ARCH=x86_64
fi
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "aarch64" ]; then
echo "Unknown architecture: $ARCH"
exit $S_FAILED
fi


function compare() {
local actual=$1
local expect=$2
if [ ! -f "$expect" ]; then
MSG="expected output file \"${BLOD_C}$expect${END_C}\" not found!"
return $S_FAILED
fi
IFS=''
while read -r line; do
local matched=$(grep -m1 -a "$line" < "$actual")
if [ -z "$matched" ]; then
MSG="pattern \"${BLOD_C}$line${END_C}\" not matched!"
unset IFS
return $S_FAILED
fi
done < "$expect"
unset IFS
return $S_PASS
}

function run_and_compare() {
local args=$1
local expect=$2
local actual=$3

echo -ne " run with \"${BLOD_C}$args${END_C}\": "

make -C "$ROOT" A="$APP" $args > "$actual" 2>&1
if [ $? -ne 0 ]; then
return $S_BUILD_FAILED
fi

TIMEFORMAT='%3Rs'
RUN_TIME=$( { time { timeout --foreground $TIMEOUT make -C "$ROOT" $args justrun > "$actual" 2>&1; }; } 2>&1 )
local res=$?
if [ $res == 124 ]; then
return $S_TIMEOUT
elif [ $res -ne 0 ]; then
return $S_FAILED
fi

compare "$actual" "$expect"
if [ $? -ne 0 ]; then
return $S_FAILED
else
return $S_PASS
fi
}


function test_one() {
local args=$1
local expect="$APP/$2"
local actual="$APP/actual.out"
args="$args ARCH=$ARCH ACCEL=n"
rm -f "$actual"

MSG=
run_and_compare "$args" "$expect" "$actual"
local res=$?

if [ $res -ne $S_PASS ]; then
EXIT_STATUS=$res
if [ $res == $S_FAILED ]; then
echo -e "${RED_C}failed!${END_C} $RUN_TIME"
elif [ $res == $S_TIMEOUT ]; then
echo -e "${YELLOW_C}timeout!${END_C} $RUN_TIME"
elif [ $res == $S_BUILD_FAILED ]; then
echo -e "${RED_C}build failed!${END_C}"
fi
if [ ! -z "$MSG" ]; then
echo -e " $MSG"
fi
echo -e "${RED_C}actual output${END_C}:"
cat "$actual"
else
echo -e "${GREEN_C}passed!${END_C} $RUN_TIME"
rm -f "$actual"
fi
}

# TODO: add more testcases
test_list=(
"nimbos"
)

for t in ${test_list[@]}; do
APP=$(realpath "$(pwd)/apps/$t")
make -C "$ROOT" user_apps AX_TESTCASE=$t
echo -e "${CYAN_C}Testing${END_C} $t:"
source "$APP/test_cmd"
done

echo -e "test script exited with: $EXIT_STATUS"
exit $EXIT_STATUS
23 changes: 10 additions & 13 deletions src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
//! Now these apps are loaded into memory as a part of the kernel image.
use core::arch::global_asm;

use alloc::vec;
use alloc::vec::Vec;
use axhal::paging::MappingFlags;
use memory_addr::VirtAddr;
Expand Down Expand Up @@ -57,7 +56,6 @@ pub(crate) fn get_app_data_by_name(name: &str) -> Option<&'static [u8]> {
}

/// List all apps.
#[allow(unused)]
pub(crate) fn list_apps() {
info!("/**** APPS ****");
let app_count = get_app_count();
Expand All @@ -76,8 +74,9 @@ pub struct ELFSegment {
/// The flags of the segment which is used to set the page table entry
pub flags: MappingFlags,
/// The data of the segment
#[allow(unused)]
pub data: Vec<u8>,
pub data: &'static [u8],
/// The offset of the segment relative to the start of the page
pub offset: usize,
}

/// The information of a given ELF file
Expand All @@ -100,13 +99,15 @@ pub(crate) fn load_user_app(name: &str) -> ELFInfo {
use xmas_elf::program::{Flags, SegmentData};
use xmas_elf::{header, ElfFile};

let elf = ElfFile::new(get_app_data_by_name(name).expect("invalid APP name"))
.expect("invalid ELF file");
let elf = ElfFile::new(
get_app_data_by_name(name).unwrap_or_else(|| panic!("failed to get app: {}", name)),
)
.expect("invalid ELF file");
let elf_header = elf.header;

let elf_magic_number = elf_header.pt1.magic;

assert_eq!(elf_magic_number, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
assert_eq!(elf_magic_number, *b"\x7fELF", "invalid elf!");

assert_eq!(
elf.header.pt2.type_().as_type(),
Expand Down Expand Up @@ -153,19 +154,15 @@ pub(crate) fn load_user_app(name: &str) -> ELFInfo {
let ed_vaddr_align =
VirtAddr::from((ph.virtual_addr() + ph.mem_size()) as usize).align_up_4k();
let data = match ph.get_data(&elf).unwrap() {
SegmentData::Undefined(data) => {
// fill start_vaddr_align to start_vaddr with 0
let mut extend_data = vec![0; st_vaddr.as_usize() - st_vaddr_align.as_usize()];
extend_data.extend_from_slice(data);
extend_data
}
SegmentData::Undefined(data) => data,
_ => panic!("failed to get ELF segment data"),
};
segments.push(ELFSegment {
start_vaddr: st_vaddr_align,
size: ed_vaddr_align.as_usize() - st_vaddr_align.as_usize(),
flags: into_mapflag(ph.flags()),
data,
offset: st_vaddr.as_usize() - st_vaddr_align.as_usize(),
});
});
ELFInfo {
Expand Down
26 changes: 17 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,29 @@ mod loader;
mod mm;
mod syscall;
mod task;
use alloc::sync::Arc;
use alloc::{sync::Arc, vec::Vec};

use axhal::arch::UspaceContext;
use axsync::Mutex;

const USER_STACK_SIZE: usize = 4096;
const USER_STACK_SIZE: usize = 0x10000;
const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB

#[no_mangle]
fn main() {
let (entry_vaddr, ustack_top, uspace) = mm::load_user_app("hello_world").unwrap();
let user_task = task::spawn_user_task(
Arc::new(Mutex::new(uspace)),
UspaceContext::new(entry_vaddr.into(), ustack_top, 2333),
);
let exit_code = user_task.join();
info!("User task exited with code: {:?}", exit_code);
loader::list_apps();
let testcases: Vec<&'static str> = option_env!("AX_TESTCASES_LIST")
.unwrap_or_else(|| "Please specify the testcases list by making user_apps")
.split(',')
.filter(|&x| !x.is_empty())
.collect();
for testcase in testcases {
let (entry_vaddr, ustack_top, uspace) = mm::load_user_app(testcase).unwrap();
let user_task = task::spawn_user_task(
Arc::new(Mutex::new(uspace)),
UspaceContext::new(entry_vaddr.into(), ustack_top, 2333),
);
let exit_code = user_task.join();
info!("User task {} exited with code: {:?}", testcase, exit_code);
}
}
Loading

0 comments on commit f87e387

Please sign in to comment.