Add performance profiler for threads and system calls

This commit is contained in:
He Sun 2020-01-17 11:38:20 +08:00 committed by tate.thl
parent a1e003ebdb
commit 74fad28938
9 changed files with 923 additions and 484 deletions

@ -50,6 +50,8 @@ enclave {
*/
int occlum_ocall_exec_thread_async(int libos_tid);
int occlum_ocall_thread_getcpuclock([out] struct timespec* ts) propagate_errno;
void occlum_ocall_gettimeofday([out] struct timeval* tv);
void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts);

@ -86,4 +86,5 @@ use self::task::Task;
use super::*;
use fs::{File, FileRef, FileTable};
use misc::ResourceLimitsRef;
use time::GLOBAL_PROFILER;
use vm::ProcessVM;

@ -98,11 +98,25 @@ pub fn run_task(libos_tid: pid_t, host_tid: pid_t) -> Result<i32> {
(pid, task)
};
#[cfg(feature = "syscall_timing")]
GLOBAL_PROFILER
.lock()
.unwrap()
.thread_enter()
.expect("unexpected error from profiler to enter thread");
unsafe {
// task may only be modified by this function; so no lock is needed
do_run_task(task);
}
#[cfg(feature = "syscall_timing")]
GLOBAL_PROFILER
.lock()
.unwrap()
.thread_exit()
.expect("unexpected error from profiler to exit thread");
let (exit_status, parent_pid) = {
let mut process = new_process.lock().unwrap();
let parent = process.get_parent().lock().unwrap();

@ -1,330 +0,0 @@
//! Syscall numbers
pub const SYS_READ: u32 = 0;
pub const SYS_WRITE: u32 = 1;
pub const SYS_OPEN: u32 = 2;
pub const SYS_CLOSE: u32 = 3;
pub const SYS_STAT: u32 = 4;
pub const SYS_FSTAT: u32 = 5;
pub const SYS_LSTAT: u32 = 6;
pub const SYS_POLL: u32 = 7;
pub const SYS_LSEEK: u32 = 8;
pub const SYS_MMAP: u32 = 9;
pub const SYS_MPROTECT: u32 = 10;
pub const SYS_MUNMAP: u32 = 11;
pub const SYS_BRK: u32 = 12;
pub const SYS_RT_SIGACTION: u32 = 13;
pub const SYS_RT_SIGPROCMASK: u32 = 14;
pub const SYS_RT_SIGRETURN: u32 = 15;
pub const SYS_IOCTL: u32 = 16;
pub const SYS_PREAD64: u32 = 17;
pub const SYS_PWRITE64: u32 = 18;
pub const SYS_READV: u32 = 19;
pub const SYS_WRITEV: u32 = 20;
pub const SYS_ACCESS: u32 = 21;
pub const SYS_PIPE: u32 = 22;
pub const SYS_SELECT: u32 = 23;
pub const SYS_SCHED_YIELD: u32 = 24;
pub const SYS_MREMAP: u32 = 25;
pub const SYS_MSYNC: u32 = 26;
pub const SYS_MINCORE: u32 = 27;
pub const SYS_MADVISE: u32 = 28;
pub const SYS_SHMGET: u32 = 29;
pub const SYS_SHMAT: u32 = 30;
pub const SYS_SHMCTL: u32 = 31;
pub const SYS_DUP: u32 = 32;
pub const SYS_DUP2: u32 = 33;
pub const SYS_PAUSE: u32 = 34;
pub const SYS_NANOSLEEP: u32 = 35;
pub const SYS_GETITIMER: u32 = 36;
pub const SYS_ALARM: u32 = 37;
pub const SYS_SETITIMER: u32 = 38;
pub const SYS_GETPID: u32 = 39;
pub const SYS_SENDFILE: u32 = 40;
pub const SYS_SOCKET: u32 = 41;
pub const SYS_CONNECT: u32 = 42;
pub const SYS_ACCEPT: u32 = 43;
pub const SYS_SENDTO: u32 = 44;
pub const SYS_RECVFROM: u32 = 45;
pub const SYS_SENDMSG: u32 = 46;
pub const SYS_RECVMSG: u32 = 47;
pub const SYS_SHUTDOWN: u32 = 48;
pub const SYS_BIND: u32 = 49;
pub const SYS_LISTEN: u32 = 50;
pub const SYS_GETSOCKNAME: u32 = 51;
pub const SYS_GETPEERNAME: u32 = 52;
pub const SYS_SOCKETPAIR: u32 = 53;
pub const SYS_SETSOCKOPT: u32 = 54;
pub const SYS_GETSOCKOPT: u32 = 55;
pub const SYS_CLONE: u32 = 56;
pub const SYS_FORK: u32 = 57;
pub const SYS_VFORK: u32 = 58;
pub const SYS_EXECVE: u32 = 59;
pub const SYS_EXIT: u32 = 60;
pub const SYS_WAIT4: u32 = 61;
pub const SYS_KILL: u32 = 62;
pub const SYS_UNAME: u32 = 63;
pub const SYS_SEMGET: u32 = 64;
pub const SYS_SEMOP: u32 = 65;
pub const SYS_SEMCTL: u32 = 66;
pub const SYS_SHMDT: u32 = 67;
pub const SYS_MSGGET: u32 = 68;
pub const SYS_MSGSND: u32 = 69;
pub const SYS_MSGRCV: u32 = 70;
pub const SYS_MSGCTL: u32 = 71;
pub const SYS_FCNTL: u32 = 72;
pub const SYS_FLOCK: u32 = 73;
pub const SYS_FSYNC: u32 = 74;
pub const SYS_FDATASYNC: u32 = 75;
pub const SYS_TRUNCATE: u32 = 76;
pub const SYS_FTRUNCATE: u32 = 77;
pub const SYS_GETDENTS: u32 = 78;
pub const SYS_GETCWD: u32 = 79;
pub const SYS_CHDIR: u32 = 80;
pub const SYS_FCHDIR: u32 = 81;
pub const SYS_RENAME: u32 = 82;
pub const SYS_MKDIR: u32 = 83;
pub const SYS_RMDIR: u32 = 84;
pub const SYS_CREAT: u32 = 85;
pub const SYS_LINK: u32 = 86;
pub const SYS_UNLINK: u32 = 87;
pub const SYS_SYMLINK: u32 = 88;
pub const SYS_READLINK: u32 = 89;
pub const SYS_CHMOD: u32 = 90;
pub const SYS_FCHMOD: u32 = 91;
pub const SYS_CHOWN: u32 = 92;
pub const SYS_FCHOWN: u32 = 93;
pub const SYS_LCHOWN: u32 = 94;
pub const SYS_UMASK: u32 = 95;
pub const SYS_GETTIMEOFDAY: u32 = 96;
pub const SYS_GETRLIMIT: u32 = 97;
pub const SYS_GETRUSAGE: u32 = 98;
pub const SYS_SYSINFO: u32 = 99;
pub const SYS_TIMES: u32 = 100;
pub const SYS_PTRACE: u32 = 101;
pub const SYS_GETUID: u32 = 102;
pub const SYS_SYSLOG: u32 = 103;
pub const SYS_GETGID: u32 = 104;
pub const SYS_SETUID: u32 = 105;
pub const SYS_SETGID: u32 = 106;
pub const SYS_GETEUID: u32 = 107;
pub const SYS_GETEGID: u32 = 108;
pub const SYS_SETPGID: u32 = 109;
pub const SYS_GETPPID: u32 = 110;
pub const SYS_GETPGRP: u32 = 111;
pub const SYS_SETSID: u32 = 112;
pub const SYS_SETREUID: u32 = 113;
pub const SYS_SETREGID: u32 = 114;
pub const SYS_GETGROUPS: u32 = 115;
pub const SYS_SETGROUPS: u32 = 116;
pub const SYS_SETRESUID: u32 = 117;
pub const SYS_GETRESUID: u32 = 118;
pub const SYS_SETRESGID: u32 = 119;
pub const SYS_GETRESGID: u32 = 120;
pub const SYS_GETPGID: u32 = 121;
pub const SYS_SETFSUID: u32 = 122;
pub const SYS_SETFSGID: u32 = 123;
pub const SYS_GETSID: u32 = 124;
pub const SYS_CAPGET: u32 = 125;
pub const SYS_CAPSET: u32 = 126;
pub const SYS_RT_SIGPENDING: u32 = 127;
pub const SYS_RT_SIGTIMEDWAIT: u32 = 128;
pub const SYS_RT_SIGQUEUEINFO: u32 = 129;
pub const SYS_RT_SIGSUSPEND: u32 = 130;
pub const SYS_SIGALTSTACK: u32 = 131;
pub const SYS_UTIME: u32 = 132;
pub const SYS_MKNOD: u32 = 133;
pub const SYS_USELIB: u32 = 134;
pub const SYS_PERSONALITY: u32 = 135;
pub const SYS_USTAT: u32 = 136;
pub const SYS_STATFS: u32 = 137;
pub const SYS_FSTATFS: u32 = 138;
pub const SYS_SYSFS: u32 = 139;
pub const SYS_GETPRIORITY: u32 = 140;
pub const SYS_SETPRIORITY: u32 = 141;
pub const SYS_SCHED_SETPARAM: u32 = 142;
pub const SYS_SCHED_GETPARAM: u32 = 143;
pub const SYS_SCHED_SETSCHEDULER: u32 = 144;
pub const SYS_SCHED_GETSCHEDULER: u32 = 145;
pub const SYS_SCHED_GET_PRIORITY_MAX: u32 = 146;
pub const SYS_SCHED_GET_PRIORITY_MIN: u32 = 147;
pub const SYS_SCHED_RR_GET_INTERVAL: u32 = 148;
pub const SYS_MLOCK: u32 = 149;
pub const SYS_MUNLOCK: u32 = 150;
pub const SYS_MLOCKALL: u32 = 151;
pub const SYS_MUNLOCKALL: u32 = 152;
pub const SYS_VHANGUP: u32 = 153;
pub const SYS_MODIFY_LDT: u32 = 154;
pub const SYS_PIVOT_ROOT: u32 = 155;
pub const SYS__SYSCTL: u32 = 156;
pub const SYS_PRCTL: u32 = 157;
pub const SYS_ARCH_PRCTL: u32 = 158;
pub const SYS_ADJTIMEX: u32 = 159;
pub const SYS_SETRLIMIT: u32 = 160;
pub const SYS_CHROOT: u32 = 161;
pub const SYS_SYNC: u32 = 162;
pub const SYS_ACCT: u32 = 163;
pub const SYS_SETTIMEOFDAY: u32 = 164;
pub const SYS_MOUNT: u32 = 165;
pub const SYS_UMOUNT2: u32 = 166;
pub const SYS_SWAPON: u32 = 167;
pub const SYS_SWAPOFF: u32 = 168;
pub const SYS_REBOOT: u32 = 169;
pub const SYS_SETHOSTNAME: u32 = 170;
pub const SYS_SETDOMAINNAME: u32 = 171;
pub const SYS_IOPL: u32 = 172;
pub const SYS_IOPERM: u32 = 173;
pub const SYS_CREATE_MODULE: u32 = 174;
pub const SYS_INIT_MODULE: u32 = 175;
pub const SYS_DELETE_MODULE: u32 = 176;
pub const SYS_GET_KERNEL_SYMS: u32 = 177;
pub const SYS_QUERY_MODULE: u32 = 178;
pub const SYS_QUOTACTL: u32 = 179;
pub const SYS_NFSSERVCTL: u32 = 180;
pub const SYS_GETPMSG: u32 = 181;
pub const SYS_PUTPMSG: u32 = 182;
pub const SYS_AFS_SYSCALL: u32 = 183;
pub const SYS_TUXCALL: u32 = 184;
pub const SYS_SECURITY: u32 = 185;
pub const SYS_GETTID: u32 = 186;
pub const SYS_READAHEAD: u32 = 187;
pub const SYS_SETXATTR: u32 = 188;
pub const SYS_LSETXATTR: u32 = 189;
pub const SYS_FSETXATTR: u32 = 190;
pub const SYS_GETXATTR: u32 = 191;
pub const SYS_LGETXATTR: u32 = 192;
pub const SYS_FGETXATTR: u32 = 193;
pub const SYS_LISTXATTR: u32 = 194;
pub const SYS_LLISTXATTR: u32 = 195;
pub const SYS_FLISTXATTR: u32 = 196;
pub const SYS_REMOVEXATTR: u32 = 197;
pub const SYS_LREMOVEXATTR: u32 = 198;
pub const SYS_FREMOVEXATTR: u32 = 199;
pub const SYS_TKILL: u32 = 200;
pub const SYS_TIME: u32 = 201;
pub const SYS_FUTEX: u32 = 202;
pub const SYS_SCHED_SETAFFINITY: u32 = 203;
pub const SYS_SCHED_GETAFFINITY: u32 = 204;
pub const SYS_SET_THREAD_AREA: u32 = 205;
pub const SYS_IO_SETUP: u32 = 206;
pub const SYS_IO_DESTROY: u32 = 207;
pub const SYS_IO_GETEVENTS: u32 = 208;
pub const SYS_IO_SUBMIT: u32 = 209;
pub const SYS_IO_CANCEL: u32 = 210;
pub const SYS_GET_THREAD_AREA: u32 = 211;
pub const SYS_LOOKUP_DCOOKIE: u32 = 212;
pub const SYS_EPOLL_CREATE: u32 = 213;
pub const SYS_EPOLL_CTL_OLD: u32 = 214;
pub const SYS_EPOLL_WAIT_OLD: u32 = 215;
pub const SYS_REMAP_FILE_PAGES: u32 = 216;
pub const SYS_GETDENTS64: u32 = 217;
pub const SYS_SET_TID_ADDRESS: u32 = 218;
pub const SYS_RESTART_SYSCALL: u32 = 219;
pub const SYS_SEMTIMEDOP: u32 = 220;
pub const SYS_FADVISE64: u32 = 221;
pub const SYS_TIMER_CREATE: u32 = 222;
pub const SYS_TIMER_SETTIME: u32 = 223;
pub const SYS_TIMER_GETTIME: u32 = 224;
pub const SYS_TIMER_GETOVERRUN: u32 = 225;
pub const SYS_TIMER_DELETE: u32 = 226;
pub const SYS_CLOCK_SETTIME: u32 = 227;
pub const SYS_CLOCK_GETTIME: u32 = 228;
pub const SYS_CLOCK_GETRES: u32 = 229;
pub const SYS_CLOCK_NANOSLEEP: u32 = 230;
pub const SYS_EXIT_GROUP: u32 = 231;
pub const SYS_EPOLL_WAIT: u32 = 232;
pub const SYS_EPOLL_CTL: u32 = 233;
pub const SYS_TGKILL: u32 = 234;
pub const SYS_UTIMES: u32 = 235;
pub const SYS_VSERVER: u32 = 236;
pub const SYS_MBIND: u32 = 237;
pub const SYS_SET_MEMPOLICY: u32 = 238;
pub const SYS_GET_MEMPOLICY: u32 = 239;
pub const SYS_MQ_OPEN: u32 = 240;
pub const SYS_MQ_UNLINK: u32 = 241;
pub const SYS_MQ_TIMEDSEND: u32 = 242;
pub const SYS_MQ_TIMEDRECEIVE: u32 = 243;
pub const SYS_MQ_NOTIFY: u32 = 244;
pub const SYS_MQ_GETSETATTR: u32 = 245;
pub const SYS_KEXEC_LOAD: u32 = 246;
pub const SYS_WAITID: u32 = 247;
pub const SYS_ADD_KEY: u32 = 248;
pub const SYS_REQUEST_KEY: u32 = 249;
pub const SYS_KEYCTL: u32 = 250;
pub const SYS_IOPRIO_SET: u32 = 251;
pub const SYS_IOPRIO_GET: u32 = 252;
pub const SYS_INOTIFY_INIT: u32 = 253;
pub const SYS_INOTIFY_ADD_WATCH: u32 = 254;
pub const SYS_INOTIFY_RM_WATCH: u32 = 255;
pub const SYS_MIGRATE_PAGES: u32 = 256;
pub const SYS_OPENAT: u32 = 257;
pub const SYS_MKDIRAT: u32 = 258;
pub const SYS_MKNODAT: u32 = 259;
pub const SYS_FCHOWNAT: u32 = 260;
pub const SYS_FUTIMESAT: u32 = 261;
pub const SYS_NEWFSTATAT: u32 = 262;
pub const SYS_UNLINKAT: u32 = 263;
pub const SYS_RENAMEAT: u32 = 264;
pub const SYS_LINKAT: u32 = 265;
pub const SYS_SYMLINKAT: u32 = 266;
pub const SYS_READLINKAT: u32 = 267;
pub const SYS_FCHMODAT: u32 = 268;
pub const SYS_FACCESSAT: u32 = 269;
pub const SYS_PSELECT6: u32 = 270;
pub const SYS_PPOLL: u32 = 271;
pub const SYS_UNSHARE: u32 = 272;
pub const SYS_SET_ROBUST_LIST: u32 = 273;
pub const SYS_GET_ROBUST_LIST: u32 = 274;
pub const SYS_SPLICE: u32 = 275;
pub const SYS_TEE: u32 = 276;
pub const SYS_SYNC_FILE_RANGE: u32 = 277;
pub const SYS_VMSPLICE: u32 = 278;
pub const SYS_MOVE_PAGES: u32 = 279;
pub const SYS_UTIMENSAT: u32 = 280;
pub const SYS_EPOLL_PWAIT: u32 = 281;
pub const SYS_SIGNALFD: u32 = 282;
pub const SYS_TIMERFD_CREATE: u32 = 283;
pub const SYS_EVENTFD: u32 = 284;
pub const SYS_FALLOCATE: u32 = 285;
pub const SYS_TIMERFD_SETTIME: u32 = 286;
pub const SYS_TIMERFD_GETTIME: u32 = 287;
pub const SYS_ACCEPT4: u32 = 288;
pub const SYS_SIGNALFD4: u32 = 289;
pub const SYS_EVENTFD2: u32 = 290;
pub const SYS_EPOLL_CREATE1: u32 = 291;
pub const SYS_DUP3: u32 = 292;
pub const SYS_PIPE2: u32 = 293;
pub const SYS_INOTIFY_INIT1: u32 = 294;
pub const SYS_PREADV: u32 = 295;
pub const SYS_PWRITEV: u32 = 296;
pub const SYS_RT_TGSIGQUEUEINFO: u32 = 297;
pub const SYS_PERF_EVENT_OPEN: u32 = 298;
pub const SYS_RECVMMSG: u32 = 299;
pub const SYS_FANOTIFY_INIT: u32 = 300;
pub const SYS_FANOTIFY_MARK: u32 = 301;
pub const SYS_PRLIMIT64: u32 = 302;
pub const SYS_NAME_TO_HANDLE_AT: u32 = 303;
pub const SYS_OPEN_BY_HANDLE_AT: u32 = 304;
pub const SYS_CLOCK_ADJTIME: u32 = 305;
pub const SYS_SYNCFS: u32 = 306;
pub const SYS_SENDMMSG: u32 = 307;
pub const SYS_SETNS: u32 = 308;
pub const SYS_GETCPU: u32 = 309;
pub const SYS_PROCESS_VM_READV: u32 = 310;
pub const SYS_PROCESS_VM_WRITEV: u32 = 311;
pub const SYS_KCMP: u32 = 312;
pub const SYS_FINIT_MODULE: u32 = 313;
pub const SYS_SCHED_SETATTR: u32 = 314;
pub const SYS_SCHED_GETATTR: u32 = 315;
pub const SYS_RENAMEAT2: u32 = 316;
pub const SYS_SECCOMP: u32 = 317;
pub const SYS_GETRANDOM: u32 = 318;
pub const SYS_MEMFD_CREATE: u32 = 319;
pub const SYS_KEXEC_FILE_LOAD: u32 = 320;
pub const SYS_BPF: u32 = 321;
pub const SYS_EXECVEAT: u32 = 322;
pub const SYS_USERFAULTFD: u32 = 323;
pub const SYS_MEMBARRIER: u32 = 324;
pub const SYS_MLOCK2: u32 = 325;
pub const SYS_SPAWN: u32 = 360;

@ -6,32 +6,30 @@
//! 2. Do some bound checks then call `dispatch_syscall` (at this file)
//! 3. Dispatch the syscall to `do_*` (at this file)
//! 4. Do some memory checks then call `mod::do_*` (at each module)
pub use self::syscall_num::SyscallNum;
use fs::{File, FileDesc, FileRef, Stat};
use misc::{resource_t, rlimit_t, utsname_t};
use net::{msghdr, msghdr_mut, AsSocket, AsUnixSocket, SocketFile, UnixSocketFile};
use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp};
use std::any::Any;
use std::convert::TryFrom;
use std::ffi::{CStr, CString};
use std::io::{Read, Seek, SeekFrom, Write};
use std::ptr;
use time::{clockid_t, timespec_t, timeval_t};
use time::{clockid_t, timespec_t, timeval_t, GLOBAL_PROFILER};
use util::mem_util::from_user::*;
use vm::{MMapFlags, VMPerms};
use {fs, process, std, vm};
use super::*;
use self::consts::*;
use std::any::Any;
use std::io::{Read, Seek, SeekFrom, Write};
mod syscall_num;
// Use the internal syscall wrappers from sgx_tstd
//use std::libc_fs as fs;
//use std::libc_io as io;
mod consts;
static mut SYSCALL_TIMING: [usize; 361] = [0; 361];
#[no_mangle]
#[deny(unreachable_patterns)]
pub extern "C" fn dispatch_syscall(
@ -43,167 +41,159 @@ pub extern "C" fn dispatch_syscall(
arg4: isize,
arg5: isize,
) -> isize {
debug!(
"syscall tid:{}, num:{}: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
process::do_gettid(),
num,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5
);
#[cfg(feature = "syscall_timing")]
let time_start = {
static mut LAST_PRINT: usize = 0;
let time = crate::time::do_gettimeofday().as_usec();
unsafe {
if time / 1000000 / 5 > LAST_PRINT {
LAST_PRINT = time / 1000000 / 5;
print_syscall_timing();
}
}
time
};
let pid = process::do_gettid();
let syscall_num = SyscallNum::try_from(num).unwrap();
let ret = match num {
debug!(
"syscall tid:{}, {:?}: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
pid, syscall_num, arg0, arg1, arg2, arg3, arg4, arg5
);
#[cfg(feature = "syscall_timing")]
GLOBAL_PROFILER
.lock()
.unwrap()
.syscall_enter(syscall_num)
.expect("unexpected error from profiler to enter syscall");
use self::syscall_num::SyscallNum::*;
let ret = match syscall_num {
// file
SYS_OPEN => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
SYS_CLOSE => fs::do_close(arg0 as FileDesc),
SYS_READ => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SYS_WRITE => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
SYS_PREAD64 => fs::do_pread(
SysOpen => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
SysClose => fs::do_close(arg0 as FileDesc),
SysRead => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SysWrite => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
SysPread64 => fs::do_pread(
arg0 as FileDesc,
arg1 as *mut u8,
arg2 as usize,
arg3 as usize,
),
SYS_PWRITE64 => fs::do_pwrite(
SysPwrite64 => fs::do_pwrite(
arg0 as FileDesc,
arg1 as *const u8,
arg2 as usize,
arg3 as usize,
),
SYS_READV => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SYS_WRITEV => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SYS_STAT => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat),
SYS_FSTAT => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat),
SYS_LSTAT => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat),
SYS_ACCESS => fs::do_access(arg0 as *const i8, arg1 as u32),
SYS_FACCESSAT => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
SYS_LSEEK => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
SYS_FSYNC => fs::do_fsync(arg0 as FileDesc),
SYS_FDATASYNC => fs::do_fdatasync(arg0 as FileDesc),
SYS_TRUNCATE => fs::do_truncate(arg0 as *const i8, arg1 as usize),
SYS_FTRUNCATE => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize),
SYS_GETDENTS64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SYS_SYNC => fs::do_sync(),
SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize),
SYS_CHDIR => fs::do_chdir(arg0 as *mut i8),
SYS_RENAME => fs::do_rename(arg0 as *const i8, arg1 as *const i8),
SYS_MKDIR => fs::do_mkdir(arg0 as *const i8, arg1 as usize),
SYS_RMDIR => fs::do_rmdir(arg0 as *const i8),
SYS_LINK => fs::do_link(arg0 as *const i8, arg1 as *const i8),
SYS_UNLINK => fs::do_unlink(arg0 as *const i8),
SYS_READLINK => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
SYS_SENDFILE => fs::do_sendfile(
SysReadv => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SysWritev => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SysStat => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat),
SysFstat => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat),
SysLstat => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat),
SysAccess => fs::do_access(arg0 as *const i8, arg1 as u32),
SysFaccessat => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
SysLseek => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
SysFsync => fs::do_fsync(arg0 as FileDesc),
SysFdatasync => fs::do_fdatasync(arg0 as FileDesc),
SysTruncate => fs::do_truncate(arg0 as *const i8, arg1 as usize),
SysFtruncate => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize),
SysGetdents64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SysSync => fs::do_sync(),
SysGetcwd => do_getcwd(arg0 as *mut u8, arg1 as usize),
SysChdir => fs::do_chdir(arg0 as *mut i8),
SysRename => fs::do_rename(arg0 as *const i8, arg1 as *const i8),
SysMkdir => fs::do_mkdir(arg0 as *const i8, arg1 as usize),
SysRmdir => fs::do_rmdir(arg0 as *const i8),
SysLink => fs::do_link(arg0 as *const i8, arg1 as *const i8),
SysUnlink => fs::do_unlink(arg0 as *const i8),
SysReadlink => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
SysSendfile => fs::do_sendfile(
arg0 as FileDesc,
arg1 as FileDesc,
arg2 as *mut off_t,
arg3 as usize,
),
SYS_FCNTL => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
SYS_IOCTL => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
SysFcntl => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
SysIoctl => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
// IO multiplexing
SYS_SELECT => net::do_select(
// Io multiplexing
SysSelect => net::do_select(
arg0 as c_int,
arg1 as *mut libc::fd_set,
arg2 as *mut libc::fd_set,
arg3 as *mut libc::fd_set,
arg4 as *const libc::timeval,
),
SYS_POLL => net::do_poll(
SysPoll => net::do_poll(
arg0 as *mut libc::pollfd,
arg1 as libc::nfds_t,
arg2 as c_int,
),
SYS_EPOLL_CREATE => net::do_epoll_create(arg0 as c_int),
SYS_EPOLL_CREATE1 => net::do_epoll_create1(arg0 as c_int),
SYS_EPOLL_CTL => net::do_epoll_ctl(
SysEpollCreate => net::do_epoll_create(arg0 as c_int),
SysEpollCreate1 => net::do_epoll_create1(arg0 as c_int),
SysEpollCtl => net::do_epoll_ctl(
arg0 as c_int,
arg1 as c_int,
arg2 as c_int,
arg3 as *const libc::epoll_event,
),
SYS_EPOLL_WAIT => net::do_epoll_wait(
SysEpollWait => net::do_epoll_wait(
arg0 as c_int,
arg1 as *mut libc::epoll_event,
arg2 as c_int,
arg3 as c_int,
),
SYS_EPOLL_PWAIT => net::do_epoll_pwait(
SysEpollPwait => net::do_epoll_pwait(
arg0 as c_int,
arg1 as *mut libc::epoll_event,
arg2 as c_int,
arg3 as c_int,
arg4 as *const usize, //TODO:add sigset_t
arg4 as *const usize, //Todo:add sigset_t
),
// process
SYS_EXIT => do_exit(arg0 as i32),
SYS_SPAWN => do_spawn(
SysExit => do_exit(arg0 as i32),
SysSpawn => do_spawn(
arg0 as *mut u32,
arg1 as *mut i8,
arg2 as *const *const i8,
arg3 as *const *const i8,
arg4 as *const FdOp,
),
SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32),
SysWait4 => do_wait4(arg0 as i32, arg1 as *mut i32),
SYS_GETPID => do_getpid(),
SYS_GETTID => do_gettid(),
SYS_GETPPID => do_getppid(),
SYS_GETPGID => do_getpgid(),
SysGetpid => do_getpid(),
SysGettid => do_gettid(),
SysGetppid => do_getppid(),
SysGetpgid => do_getpgid(),
SYS_GETUID => do_getuid(),
SYS_GETGID => do_getgid(),
SYS_GETEUID => do_geteuid(),
SYS_GETEGID => do_getegid(),
SysGetuid => do_getuid(),
SysGetgid => do_getgid(),
SysGeteuid => do_geteuid(),
SysGetegid => do_getegid(),
SYS_RT_SIGACTION => do_rt_sigaction(),
SYS_RT_SIGPROCMASK => do_rt_sigprocmask(),
SysRtSigaction => do_rt_sigaction(),
SysRtSigprocmask => do_rt_sigprocmask(),
SYS_CLONE => do_clone(
SysClone => do_clone(
arg0 as u32,
arg1 as usize,
arg2 as *mut pid_t,
arg3 as *mut pid_t,
arg4 as usize,
),
SYS_FUTEX => do_futex(
SysFutex => do_futex(
arg0 as *const i32,
arg1 as u32,
arg2 as i32,
arg3 as i32,
arg4 as *const i32,
// TODO: accept other optional arguments
// Todo: accept other optional arguments
),
SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
SYS_SET_TID_ADDRESS => do_set_tid_address(arg0 as *mut pid_t),
SysArchPrctl => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
SysSetTidAddress => do_set_tid_address(arg0 as *mut pid_t),
// sched
SYS_SCHED_YIELD => do_sched_yield(),
SYS_SCHED_GETAFFINITY => {
SysSchedYield => do_sched_yield(),
SysSchedGetaffinity => {
do_sched_getaffinity(arg0 as pid_t, arg1 as size_t, arg2 as *mut c_uchar)
}
SYS_SCHED_SETAFFINITY => {
SysSchedSetaffinity => {
do_sched_setaffinity(arg0 as pid_t, arg1 as size_t, arg2 as *const c_uchar)
}
// memory
SYS_MMAP => do_mmap(
SysMmap => do_mmap(
arg0 as usize,
arg1 as usize,
arg2 as i32,
@ -211,31 +201,31 @@ pub extern "C" fn dispatch_syscall(
arg4 as FileDesc,
arg5 as off_t,
),
SYS_MUNMAP => do_munmap(arg0 as usize, arg1 as usize),
SYS_MREMAP => do_mremap(
SysMunmap => do_munmap(arg0 as usize, arg1 as usize),
SysMremap => do_mremap(
arg0 as usize,
arg1 as usize,
arg2 as usize,
arg3 as i32,
arg4 as usize,
),
SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
SYS_BRK => do_brk(arg0 as usize),
SysMprotect => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
SysBrk => do_brk(arg0 as usize),
SYS_PIPE => fs::do_pipe2(arg0 as *mut i32, 0),
SYS_PIPE2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32),
SYS_DUP => fs::do_dup(arg0 as FileDesc),
SYS_DUP2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc),
SYS_DUP3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
SysPipe => fs::do_pipe2(arg0 as *mut i32, 0),
SysPipe2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32),
SysDup => fs::do_dup(arg0 as FileDesc),
SysDup2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc),
SysDup3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t),
SysGettimeofday => do_gettimeofday(arg0 as *mut timeval_t),
SysClockGettime => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t),
SYS_NANOSLEEP => do_nanosleep(arg0 as *const timespec_t, arg1 as *mut timespec_t),
SysNanosleep => do_nanosleep(arg0 as *const timespec_t, arg1 as *mut timespec_t),
SYS_UNAME => do_uname(arg0 as *mut utsname_t),
SysUname => do_uname(arg0 as *mut utsname_t),
SYS_PRLIMIT64 => do_prlimit(
SysPrlimit64 => do_prlimit(
arg0 as pid_t,
arg1 as u32,
arg2 as *const rlimit_t,
@ -243,56 +233,56 @@ pub extern "C" fn dispatch_syscall(
),
// socket
SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int),
SYS_CONNECT => do_connect(
SysSocket => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int),
SysConnect => do_connect(
arg0 as c_int,
arg1 as *const libc::sockaddr,
arg2 as libc::socklen_t,
),
SYS_ACCEPT => do_accept4(
SysAccept => do_accept4(
arg0 as c_int,
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
0,
),
SYS_ACCEPT4 => do_accept4(
SysAccept4 => do_accept4(
arg0 as c_int,
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
arg3 as c_int,
),
SYS_SHUTDOWN => do_shutdown(arg0 as c_int, arg1 as c_int),
SYS_BIND => do_bind(
SysShutdown => do_shutdown(arg0 as c_int, arg1 as c_int),
SysBind => do_bind(
arg0 as c_int,
arg1 as *const libc::sockaddr,
arg2 as libc::socklen_t,
),
SYS_LISTEN => do_listen(arg0 as c_int, arg1 as c_int),
SYS_SETSOCKOPT => do_setsockopt(
SysListen => do_listen(arg0 as c_int, arg1 as c_int),
SysSetsockopt => do_setsockopt(
arg0 as c_int,
arg1 as c_int,
arg2 as c_int,
arg3 as *const c_void,
arg4 as libc::socklen_t,
),
SYS_GETSOCKOPT => do_getsockopt(
SysGetsockopt => do_getsockopt(
arg0 as c_int,
arg1 as c_int,
arg2 as c_int,
arg3 as *mut c_void,
arg4 as *mut libc::socklen_t,
),
SYS_GETPEERNAME => do_getpeername(
SysGetpeername => do_getpeername(
arg0 as c_int,
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
),
SYS_GETSOCKNAME => do_getsockname(
SysGetsockname => do_getsockname(
arg0 as c_int,
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
),
SYS_SENDTO => do_sendto(
SysSendto => do_sendto(
arg0 as c_int,
arg1 as *const c_void,
arg2 as size_t,
@ -300,7 +290,7 @@ pub extern "C" fn dispatch_syscall(
arg4 as *const libc::sockaddr,
arg5 as libc::socklen_t,
),
SYS_RECVFROM => do_recvfrom(
SysRecvfrom => do_recvfrom(
arg0 as c_int,
arg1 as *mut c_void,
arg2 as size_t,
@ -309,29 +299,27 @@ pub extern "C" fn dispatch_syscall(
arg5 as *mut libc::socklen_t,
),
SYS_SOCKETPAIR => do_socketpair(
SysSocketpair => do_socketpair(
arg0 as c_int,
arg1 as c_int,
arg2 as c_int,
arg3 as *mut c_int,
),
SYS_SENDMSG => net::do_sendmsg(arg0 as c_int, arg1 as *const msghdr, arg2 as c_int),
SYS_RECVMSG => net::do_recvmsg(arg0 as c_int, arg1 as *mut msghdr_mut, arg2 as c_int),
SysSendmsg => net::do_sendmsg(arg0 as c_int, arg1 as *const msghdr, arg2 as c_int),
SysRecvmsg => net::do_recvmsg(arg0 as c_int, arg1 as *mut msghdr_mut, arg2 as c_int),
_ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5),
};
#[cfg(feature = "syscall_timing")]
{
let time_end = crate::time::do_gettimeofday().as_usec();
let time = time_end - time_start;
unsafe {
SYSCALL_TIMING[num as usize] += time as usize;
}
}
GLOBAL_PROFILER
.lock()
.unwrap()
.syscall_exit(syscall_num, ret.is_err())
.expect("unexpected error from profiler to exit syscall");
info!("=> {:?}", ret);
info!("tid: {} => {:?} ", process::do_gettid(), ret);
match ret {
Ok(retval) => retval as isize,
@ -345,20 +333,6 @@ pub extern "C" fn dispatch_syscall(
}
}
#[cfg(feature = "syscall_timing")]
fn print_syscall_timing() {
println!("syscall timing:");
for (i, &time) in unsafe { SYSCALL_TIMING }.iter().enumerate() {
if time == 0 {
continue;
}
println!("{:>3}: {:>6} us", i, time);
}
for x in unsafe { SYSCALL_TIMING.iter_mut() } {
*x = 0;
}
}
/*
* This Rust-version of fdop correspond to the C-version one in Occlum.
* See <path_to_musl_libc>/src/process/fdop.h.

@ -0,0 +1,345 @@
use super::*;
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum SyscallNum {
SysRead = 0,
SysWrite = 1,
SysOpen = 2,
SysClose = 3,
SysStat = 4,
SysFstat = 5,
SysLstat = 6,
SysPoll = 7,
SysLseek = 8,
SysMmap = 9,
SysMprotect = 10,
SysMunmap = 11,
SysBrk = 12,
SysRtSigaction = 13,
SysRtSigprocmask = 14,
SysRtSigreturn = 15,
SysIoctl = 16,
SysPread64 = 17,
SysPwrite64 = 18,
SysReadv = 19,
SysWritev = 20,
SysAccess = 21,
SysPipe = 22,
SysSelect = 23,
SysSchedYield = 24,
SysMremap = 25,
SysMsync = 26,
SysMincore = 27,
SysMadvise = 28,
SysShmget = 29,
SysShmat = 30,
SysShmctl = 31,
SysDup = 32,
SysDup2 = 33,
SysPause = 34,
SysNanosleep = 35,
SysGetitimer = 36,
SysAlarm = 37,
SysSetitimer = 38,
SysGetpid = 39,
SysSendfile = 40,
SysSocket = 41,
SysConnect = 42,
SysAccept = 43,
SysSendto = 44,
SysRecvfrom = 45,
SysSendmsg = 46,
SysRecvmsg = 47,
SysShutdown = 48,
SysBind = 49,
SysListen = 50,
SysGetsockname = 51,
SysGetpeername = 52,
SysSocketpair = 53,
SysSetsockopt = 54,
SysGetsockopt = 55,
SysClone = 56,
SysFork = 57,
SysVfork = 58,
SysExecve = 59,
SysExit = 60,
SysWait4 = 61,
SysKill = 62,
SysUname = 63,
SysSemget = 64,
SysSemop = 65,
SysSemctl = 66,
SysShmdt = 67,
SysMsgget = 68,
SysMsgsnd = 69,
SysMsgrcv = 70,
SysMsgctl = 71,
SysFcntl = 72,
SysFlock = 73,
SysFsync = 74,
SysFdatasync = 75,
SysTruncate = 76,
SysFtruncate = 77,
SysGetdents = 78,
SysGetcwd = 79,
SysChdir = 80,
SysFchdir = 81,
SysRename = 82,
SysMkdir = 83,
SysRmdir = 84,
SysCreat = 85,
SysLink = 86,
SysUnlink = 87,
SysSymlink = 88,
SysReadlink = 89,
SysChmod = 90,
SysFchmod = 91,
SysChown = 92,
SysFchown = 93,
SysLchown = 94,
SysUmask = 95,
SysGettimeofday = 96,
SysGetrlimit = 97,
SysGetrusage = 98,
SysSysInfo = 99,
SysTimes = 100,
SysPtrace = 101,
SysGetuid = 102,
SysSysLog = 103,
SysGetgid = 104,
SysSetuid = 105,
SysSetgid = 106,
SysGeteuid = 107,
SysGetegid = 108,
SysSetpgid = 109,
SysGetppid = 110,
SysGetpgrp = 111,
SysSetsid = 112,
SysSetreuid = 113,
SysSetregid = 114,
SysGetgroups = 115,
SysSetgroups = 116,
SysSetresuid = 117,
SysGetresuid = 118,
SysSetresgid = 119,
SysGetresgid = 120,
SysGetpgid = 121,
SysSetfsuid = 122,
SysSetfsgid = 123,
SysGetsid = 124,
SysCapget = 125,
SysCapset = 126,
SysRtSigpending = 127,
SysRtSigtimedwait = 128,
SysRtSigqueueinfo = 129,
SysRtSigsuspend = 130,
SysSigaltstack = 131,
SysUtime = 132,
SysMknod = 133,
SysUselib = 134,
SysPersonality = 135,
SysUstat = 136,
SysStatfs = 137,
SysFstatfs = 138,
SysSysFs = 139,
SysGetpriority = 140,
SysSetpriority = 141,
SysSchedSetparam = 142,
SysSchedGetparam = 143,
SysSchedSetscheduler = 144,
SysSchedGetscheduler = 145,
SysSchedGetPriorityMax = 146,
SysSchedGetPriorityMin = 147,
SysSchedRrGetInterval = 148,
SysMlock = 149,
SysMunlock = 150,
SysMlockall = 151,
SysMunlockall = 152,
SysVhangup = 153,
SysModifyLdt = 154,
SysPivotRoot = 155,
SysSysCtl = 156,
SysPrctl = 157,
SysArchPrctl = 158,
SysAdjtimex = 159,
SysSetrlimit = 160,
SysChroot = 161,
SysSync = 162,
SysAcct = 163,
SysSettimeofday = 164,
SysMount = 165,
SysUmount2 = 166,
SysSwapon = 167,
SysSwapoff = 168,
SysReboot = 169,
SysSethostname = 170,
SysSetdomainname = 171,
SysIopl = 172,
SysIoperm = 173,
SysCreateModule = 174,
SysInitModule = 175,
SysDeleteModule = 176,
SysGetKernelSyms = 177,
SysQueryModule = 178,
SysQuotactl = 179,
SysNfsservctl = 180,
SysGetpmsg = 181,
SysPutpmsg = 182,
SysAfsSysCall = 183,
SysTuxcall = 184,
SysSecurity = 185,
SysGettid = 186,
SysReadahead = 187,
SysSetxattr = 188,
SysLsetxattr = 189,
SysFsetxattr = 190,
SysGetxattr = 191,
SysLgetxattr = 192,
SysFgetxattr = 193,
SysListxattr = 194,
SysLlistxattr = 195,
SysFlistxattr = 196,
SysRemovexattr = 197,
SysLremovexattr = 198,
SysFremovexattr = 199,
SysTkill = 200,
SysTime = 201,
SysFutex = 202,
SysSchedSetaffinity = 203,
SysSchedGetaffinity = 204,
SysSetThreadArea = 205,
SysIoSetup = 206,
SysIoDestroy = 207,
SysIoGetevents = 208,
SysIoSubmit = 209,
SysIoCancel = 210,
SysGetThreadArea = 211,
SysLookupDcookie = 212,
SysEpollCreate = 213,
SysEpollCtlOld = 214,
SysEpollWaitOld = 215,
SysRemapFilePages = 216,
SysGetdents64 = 217,
SysSetTidAddress = 218,
SysRestartSysCall = 219,
SysSemtimedop = 220,
SysFadvise64 = 221,
SysTimerCreate = 222,
SysTimerSettime = 223,
SysTimerGettime = 224,
SysTimerGetoverrun = 225,
SysTimerDelete = 226,
SysClockSettime = 227,
SysClockGettime = 228,
SysClockGetres = 229,
SysClockNanosleep = 230,
SysExitGroup = 231,
SysEpollWait = 232,
SysEpollCtl = 233,
SysTgkill = 234,
SysUtimes = 235,
SysVserver = 236,
SysMbind = 237,
SysSetMempolicy = 238,
SysGetMempolicy = 239,
SysMqOpen = 240,
SysMqUnlink = 241,
SysMqTimedsend = 242,
SysMqTimedreceive = 243,
SysMqNotify = 244,
SysMqGetsetattr = 245,
SysKexecLoad = 246,
SysWaitid = 247,
SysAddKey = 248,
SysRequestKey = 249,
SysKeyctl = 250,
SysIoprioSet = 251,
SysIoprioGet = 252,
SysInotifyInit = 253,
SysInotifyAddWatch = 254,
SysInotifyRmWatch = 255,
SysMigratePages = 256,
SysOpenat = 257,
SysMkdirat = 258,
SysMknodat = 259,
SysFchownat = 260,
SysFutimesat = 261,
SysNewfstatat = 262,
SysUnlinkat = 263,
SysRenameat = 264,
SysLinkat = 265,
SysSymlinkat = 266,
SysReadlinkat = 267,
SysFchmodat = 268,
SysFaccessat = 269,
SysPselect6 = 270,
SysPpoll = 271,
SysUnshare = 272,
SysSetRobustList = 273,
SysGetRobustList = 274,
SysSplice = 275,
SysTee = 276,
SysSyncFileRange = 277,
SysVmsplice = 278,
SysMovePages = 279,
SysUtimensat = 280,
SysEpollPwait = 281,
SysSignalfd = 282,
SysTimerfdCreate = 283,
SysEventfd = 284,
SysFallocate = 285,
SysTimerfdSettime = 286,
SysTimerfdGettime = 287,
SysAccept4 = 288,
SysSignalfd4 = 289,
SysEventfd2 = 290,
SysEpollCreate1 = 291,
SysDup3 = 292,
SysPipe2 = 293,
SysInotifyInit1 = 294,
SysPreadv = 295,
SysPwritev = 296,
SysRtTgsigqueueinfo = 297,
SysPerfEventOpen = 298,
SysRecvmmsg = 299,
SysFanotifyInit = 300,
SysFanotifyMark = 301,
SysPrlimit64 = 302,
SysNameToHandleAt = 303,
SysOpenByHandleAt = 304,
SysClockAdjtime = 305,
SysSyncfs = 306,
SysSendmmsg = 307,
SysSetns = 308,
SysGetcpu = 309,
SysProcessVmReadv = 310,
SysProcessVmWritev = 311,
SysKcmp = 312,
SysFinitModule = 313,
SysSchedSetattr = 314,
SysSchedGetattr = 315,
SysRenameat2 = 316,
SysSeccomp = 317,
SysGetrandom = 318,
SysMemfdCreate = 319,
SysKexecFileLoad = 320,
SysBpf = 321,
SysExecveat = 322,
SysUserfaultfd = 323,
SysMembarrier = 324,
SysMlock2 = 325,
SysSpawn = 360,
}
impl TryFrom<u32> for SyscallNum {
type Error = error::Error;
fn try_from(value: u32) -> Result<Self> {
if value > 325 && value != 360 {
return_errno!(EINVAL, "invalid syscall number");
} else {
Ok(unsafe { core::mem::transmute(value as u16) })
}
}
}

@ -1,7 +1,15 @@
use super::*;
use core::convert::TryFrom;
use process::pid_t;
use rcore_fs::dev::TimeProvider;
use rcore_fs::vfs::Timespec;
use std::time::Duration;
use std::{fmt, u64};
use syscall::SyscallNum;
use super::*;
mod profiler;
pub use profiler::GLOBAL_PROFILER;
#[allow(non_camel_case_types)]
pub type time_t = i64;
@ -18,10 +26,6 @@ pub struct timeval_t {
}
impl timeval_t {
pub fn as_usec(&self) -> usize {
(self.sec * 1000000 + self.usec) as usize
}
pub fn validate(&self) -> Result<()> {
if self.sec >= 0 && self.usec >= 0 && self.usec < 1_000_000 {
Ok(())
@ -29,6 +33,10 @@ impl timeval_t {
return_errno!(EINVAL, "invalid value for timeval_t");
}
}
pub fn as_duration(&self) -> Duration {
Duration::new(self.sec as u64, (self.usec * 1_000) as u32)
}
}
pub fn do_gettimeofday() -> timeval_t {
@ -55,9 +63,7 @@ pub struct timespec_t {
impl timespec_t {
pub fn from_raw_ptr(ptr: *const timespec_t) -> Result<timespec_t> {
let ts = unsafe { *ptr };
if ts.sec < 0 || ts.nsec < 0 || ts.nsec >= 1_000_000_000 {
return_errno!(EINVAL, "Invalid timespec fields");
}
ts.validate()?;
Ok(ts)
}
@ -68,6 +74,10 @@ impl timespec_t {
return_errno!(EINVAL, "invalid value for timespec_t");
}
}
pub fn as_duration(&self) -> Duration {
Duration::new(self.sec as u64, self.nsec as u32)
}
}
#[allow(non_camel_case_types)]
@ -126,6 +136,22 @@ pub fn do_nanosleep(req: &timespec_t) -> Result<()> {
Ok(())
}
pub fn do_thread_getcpuclock() -> Result<timespec_t> {
extern "C" {
fn occlum_ocall_thread_getcpuclock(ret: *mut c_int, tp: *mut timespec_t) -> sgx_status_t;
}
let mut tv: timespec_t = Default::default();
try_libc!({
let mut retval: i32 = 0;
let status = occlum_ocall_thread_getcpuclock(&mut retval, &mut tv as *mut timespec_t);
assert!(status == sgx_status_t::SGX_SUCCESS);
retval
});
tv.validate()?;
Ok(tv)
}
// For SEFS
pub struct OcclumTimeProvider;

@ -0,0 +1,395 @@
use super::*;
lazy_static! {
pub static ref GLOBAL_PROFILER: SgxMutex<GlobalProfiler> = SgxMutex::new(GlobalProfiler::new());
}
/// A profiler that can be used across threads.
// TODO: Use light-weight thread_local storage other than mutex
pub struct GlobalProfiler {
inner: HashMap<pid_t, ThreadProfiler>,
}
impl GlobalProfiler {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn thread_enter(&mut self) -> Result<()> {
let tid = process::do_gettid();
if self.inner.insert(tid, ThreadProfiler::new()).is_some() {
return_errno!(
EINVAL,
"global profiler should exit the thread before entering"
);
}
self.inner.get_mut(&tid).unwrap().start()
}
pub fn thread_exit(&mut self) -> Result<()> {
// A thread exits by invoking SysExit syscall which
// will never return
self.syscall_exit(SyscallNum::SysExit, false);
let tid = process::do_gettid();
println!("thread {} exits", tid);
let mut exiting_profiler = self.inner.remove(&tid).ok_or_else(|| {
errno!(
EINVAL,
"global profiler should enter a thread before exit one"
)
})?;
exiting_profiler.stop()?;
exiting_profiler.display()?;
Ok(())
}
pub fn syscall_enter(&mut self, syscall_num: SyscallNum) -> Result<()> {
let tid = process::do_gettid();
let mut prof = self.inner.get_mut(&tid).unwrap();
prof.syscall_enter(syscall_num)
}
pub fn syscall_exit(&mut self, syscall_num: SyscallNum, is_err: bool) -> Result<()> {
let tid = process::do_gettid();
let mut prof = self.inner.get_mut(&tid).unwrap();
prof.syscall_exit(syscall_num, is_err)
}
}
/// A profiler used inside a thread.
// TODO: add support for exception
#[derive(Clone)]
pub struct ThreadProfiler {
syscall_data: HashMap<SyscallNum, PerfEntry>,
start_time: ProfileTime,
status: Status,
}
impl ThreadProfiler {
pub fn new() -> Self {
Self {
syscall_data: HashMap::new(),
start_time: ProfileTime::TwoTimes {
real: Duration::new(0, 0),
cpu: Duration::new(0, 0),
},
status: Status::Stopped(TimeSummary::new(
Duration::new(0, 0),
Duration::new(0, 0),
Duration::new(0, 0),
)),
}
}
fn start(&mut self) -> Result<()> {
match self.status {
Status::Stopped(..) => {
self.status = Status::Running;
self.start_time.update()
}
_ => return_errno!(
EINVAL,
"thread profiler can only be started in stopped status"
),
}
}
fn stop(&mut self) -> Result<()> {
if self.status != Status::Running {
error!("wrong status is {:?}", self.status);
return_errno!(EINVAL, "fail to stop thread profiler");
}
let real = time::do_gettimeofday().as_duration() - self.start_time.get_realtime().unwrap();
let total_cputime =
time::do_thread_getcpuclock()?.as_duration() - self.start_time.get_cputime().unwrap();
let sys = self.get_syscall_total_time()?;
let usr = total_cputime - sys;
self.status = Status::Stopped(TimeSummary::new(real, usr, sys));
Ok(())
}
fn syscall_enter(&mut self, syscall_num: SyscallNum) -> Result<()> {
match self.status {
Status::Running => {
let mut cur_time = ProfileTime::CpuTime(Default::default());
cur_time.update()?;
self.status = Status::InSyscall {
start_cpu: cur_time,
num: syscall_num,
};
self.syscall_data
.entry(syscall_num)
.or_insert(PerfEntry::new());
Ok(())
}
_ => return_errno!(
EINVAL,
"threa profiler should be started before entering syscall"
),
}
}
fn syscall_exit(&mut self, syscall_num: SyscallNum, is_err: bool) -> Result<()> {
match self.status {
Status::InSyscall { start_cpu, num } => {
if syscall_num != num {
return_errno!(EINVAL, "syscall number mismatches");
}
self.status = Status::Running;
let syscall_cpu_time =
time::do_thread_getcpuclock()?.as_duration() - start_cpu.get_cputime().unwrap();
self.syscall_data.entry(num).and_modify(|e| {
e.update(syscall_cpu_time, is_err)
.expect("fail to update syscall data")
});
Ok(())
}
_ => return_errno!(
EINVAL,
"thread profiler should be in one syscall before exiting the syscall"
),
}
}
fn get_syscall_total_time(&self) -> Result<Duration> {
Ok(self.get_syscall_total()?.0)
}
fn get_syscall_total(&self) -> Result<(Duration, u32, u32)> {
let mut total_time: Duration = Duration::new(0, 0);
let mut total_calls: u32 = 0;
let mut total_errors: u32 = 0;
for entry in self.syscall_data.values() {
total_time += entry.get_total_time();
total_calls = entry
.get_calls()
.checked_add(total_calls)
.ok_or_else(|| errno!(EOVERFLOW, "total calls overflow"))?;
total_errors += entry.get_errors();
}
Ok((total_time, total_calls, total_errors))
}
fn display(&self) -> Result<()> {
match self.status {
Status::Stopped(report) => {
// Pretty-print the Debug formatting report of the profiled thread
println!("{:#?}", report);
// Print the syscall statistics of the profiled thread
self.display_syscall_stat()
}
_ => return_errno!(EINVAL, "thread profiler can report only in stopped status"),
}
}
/// Print the syscall statistics of the profiled thread.
///
/// The statistics consist of:
/// syscall number, the corresponding percentage of the aggregate time in all the syscalls,
/// the aggregate time, average execution time of a call, aggregate calls, aggregate errors,
/// the shortest and longest execution time of the syscall.
/// A piece of the output is:
/// syscall % time seconds us/call calls errors range(us)
/// ------------------- ------ ----------- ----------- --------- --------- -----------
/// SysWritev 0.40 0.000131 26 5 0 [12, 47]
/// SysMprotect 0.03 0.000009 4 2 0 [4, 4]
/// ------------------- ------ ----------- ----------- --------- --------- -----------
fn display_syscall_stat(&self) -> Result<()> {
println!(
"{:<19} {:>6} {:>11} {:>11} {:>9} {:>9} {}",
"syscall", "% time", "seconds", "us/call", "calls", "errors", "range(us)",
);
println!(
"{:-<19} {:-<6} {:-<11} {:-<11} {:-<9} {:-<9} {:-<11}",
"", "", "", "", "", "", ""
);
let (total_time, total_calls, total_errors) = self.get_syscall_total()?;
let mut syscall_data_ref: Vec<(&SyscallNum, &PerfEntry)> =
self.syscall_data.iter().collect();
syscall_data_ref.sort_by(|(_, entry_a), (_, entry_b)| {
entry_b.get_total_time().cmp(&(entry_a.get_total_time()))
});
for (syscall_num, entry) in syscall_data_ref {
let time_percentage =
entry.get_total_time().as_secs_f64() / total_time.as_secs_f64() * 100_f64;
println!(
"{:<19} {:>6.2} {:?}",
format!("{:?}", syscall_num),
time_percentage,
entry,
);
}
println!(
"{:-<19} {:-<6} {:-<11} {:-<11} {:-<9} {:-<9} {:-<11}",
"", "", "", "", "", "", ""
);
println!(
"{} {:>20} {:>11.6} {:>21} {:>9}",
"total",
"100",
total_time.as_secs_f64(),
total_calls,
total_errors,
);
Ok(())
}
}
#[derive(Copy, Clone)]
struct PerfEntry {
calls: u32,
total_time: Duration,
peak: Duration,
bottom: Duration,
errors: u32,
}
impl PerfEntry {
fn new() -> Self {
Self {
calls: 0,
total_time: Duration::new(0, 0),
peak: Duration::new(0, 0),
bottom: Duration::new(u64::MAX, 1_000_000_000 - 1),
errors: 0,
}
}
fn update(&mut self, time: Duration, is_err: bool) -> Result<()> {
self.calls = self
.calls
.checked_add(1)
.ok_or_else(|| errno!(EOVERFLOW, "single syscallduration addition overflow"))?;
self.total_time += time;
if time > self.peak {
self.peak = time;
}
if time < self.bottom {
self.bottom = time;
}
if is_err {
self.errors += 1;
}
Ok(())
}
fn get_average(&self) -> Duration {
if self.calls == 0 {
Duration::new(0, 0)
} else {
self.total_time / self.calls
}
}
fn get_calls(&self) -> u32 {
self.calls
}
fn get_total_time(&self) -> Duration {
self.total_time
}
fn get_errors(&self) -> u32 {
self.errors
}
}
/// Used for the display of ThreadProfiler.
/// The total execution time in secs, average execution time in microseconds,
/// total calls, total errors, the shortest and longest execution time.
/// The output looks like:
/// 0.000009 4 2 0 [4, 4]
impl fmt::Debug for PerfEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:>11.6} {:>11} {:>9} {:>9} [{}, {}]",
self.total_time.as_secs_f64(),
self.get_average().as_micros(),
self.calls,
self.errors,
self.bottom.as_micros(),
self.peak.as_micros()
)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum ProfileTime {
RealTime(Duration),
CpuTime(Duration),
TwoTimes { real: Duration, cpu: Duration },
}
impl ProfileTime {
fn get_realtime(&self) -> Option<Duration> {
match *self {
ProfileTime::RealTime(t) => Some(t),
ProfileTime::CpuTime(t) => None,
ProfileTime::TwoTimes { real, cpu } => Some(real),
}
}
fn get_cputime(&self) -> Option<Duration> {
match *self {
ProfileTime::RealTime(t) => None,
ProfileTime::CpuTime(t) => Some(t),
ProfileTime::TwoTimes { real, cpu } => Some(cpu),
}
}
fn update(&mut self) -> Result<()> {
match self {
ProfileTime::RealTime(ref mut t) => *t = time::do_gettimeofday().as_duration(),
ProfileTime::CpuTime(ref mut t) => *t = time::do_thread_getcpuclock()?.as_duration(),
ProfileTime::TwoTimes {
ref mut real,
ref mut cpu,
} => {
*real = time::do_gettimeofday().as_duration();
*cpu = time::do_thread_getcpuclock()?.as_duration();
}
}
Ok(())
}
}
/// The timing statistics about one thread.
/// These statistics consist of:
/// (i) the elapsed real time between invocation and termination
/// (ii) the CPU time running in user space
/// (iii) the CPU time running in libos
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct TimeSummary {
real: Duration,
usr: Duration,
sys: Duration,
}
impl TimeSummary {
fn new(real: Duration, usr: Duration, sys: Duration) -> Self {
Self { real, usr, sys }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum Status {
Running,
Stopped(TimeSummary),
InSyscall {
start_cpu: ProfileTime,
num: SyscallNum,
},
}

@ -1,3 +1,4 @@
#include <pthread.h>
#include <sys/time.h>
#include "ocalls.h"
@ -12,3 +13,14 @@ void occlum_ocall_clock_gettime(int clockid, struct timespec *tp) {
void occlum_ocall_nanosleep(const struct timespec* req) {
nanosleep(req, NULL);
}
int occlum_ocall_thread_getcpuclock(struct timespec *tp) {
clockid_t thread_clock_id;
int ret = pthread_getcpuclockid(pthread_self(), &thread_clock_id);
if(ret != 0) {
PAL_ERROR("failed to get clock id");
return -1;
}
return clock_gettime(thread_clock_id, tp);
}