From 90895cfb1f098ff5d965c9b90719dab04148d277 Mon Sep 17 00:00:00 2001 From: Masamichi Takagi Date: Wed, 17 Feb 2021 17:11:24 +0900 Subject: [PATCH] test: uti: add tofu examples Change-Id: I1c55c872d125201e60b4fe744af74106e1c5d3a4 --- executer/kernel/mcctrl/control.c | 9 + test/uti/tofu/README | 112 ++ test/uti/tofu/include/tof_test.h | 236 ++++ test/uti/tofu/include/tof_uapi.h | 345 ++++++ test/uti/tofu/init.sh | 39 + test/uti/tofu/with_libuti/Makefile | 20 + test/uti/tofu/with_libuti/ctrl.c | 74 ++ test/uti/tofu/with_libuti/uti_perf.c | 1503 ++++++++++++++++++++++++++ test/uti/tofu/wo_libuti/Makefile | 20 + test/uti/tofu/wo_libuti/ctrl.c | 74 ++ test/uti/tofu/wo_libuti/uti_perf.c | 1493 +++++++++++++++++++++++++ 11 files changed, 3925 insertions(+) create mode 100644 test/uti/tofu/README create mode 100644 test/uti/tofu/include/tof_test.h create mode 100644 test/uti/tofu/include/tof_uapi.h create mode 100755 test/uti/tofu/init.sh create mode 100644 test/uti/tofu/with_libuti/Makefile create mode 100644 test/uti/tofu/with_libuti/ctrl.c create mode 100644 test/uti/tofu/with_libuti/uti_perf.c create mode 100644 test/uti/tofu/wo_libuti/Makefile create mode 100644 test/uti/tofu/wo_libuti/ctrl.c create mode 100644 test/uti/tofu/wo_libuti/uti_perf.c diff --git a/executer/kernel/mcctrl/control.c b/executer/kernel/mcctrl/control.c index de034ca2..5ead3293 100644 --- a/executer/kernel/mcctrl/control.c +++ b/executer/kernel/mcctrl/control.c @@ -3185,6 +3185,15 @@ mcexec_uti_attr(ihk_os_t os, struct uti_attr_desc __user *_desc) kattr = phys_to_virt(desc.phys_attr); + { + int i; + + pr_info("%s: flag: %lx\n", __func__, (unsigned long)kattr->attr.flags); + for (i = 0; i < UTI_MAX_NUMA_DOMAINS; i+= 64) { + kprintf("%s: numa_set[%d]: %lx\n", __func__, i, (unsigned long)kattr->attr.numa_set[i / 64]); + } + } + /* Find caller cpu for later resolution of subgroups */ list_for_each_entry(cpu_topo, &ud->cpu_topology_list, chain) { if (cpu_topo->mckernel_cpu_id == kattr->parent_cpuid) { diff --git a/test/uti/tofu/README b/test/uti/tofu/README new file mode 100644 index 00000000..0318c805 --- /dev/null +++ b/test/uti/tofu/README @@ -0,0 +1,112 @@ +実行手順 +======== + +初回実行時、tofu get通信する両方のノードでtofuサブネットを設定する。 +ソース一式をビルドしたときに生成される ctrl を使用する。 +sudo ./ctrl + +tofu_perf プログラムの実行は受信側("-r"オプションを付加した方)を先にする。 +"do_recv: Measure the reaction delay, Ready" メッセージを確認したあと、 +送信側 ("-r"オプションを付加しない方) を実行する。 +"-r"オプション以外は、受信側/送信側で同じ値を指定する。 + +コマンド例 +========== + +init.shに例を示す。以下、init.shの内容を説明する。 + +以下のコマンドでcgroupsを設定する。 + +sudo bash -c 'echo "0,1,12-59" > /sys/fs/cgroup/cpuset/system.slice/cpuset.cpus' +sudo bash -c 'echo "0-7" > /sys/fs/cgroup/cpuset/system.slice/cpuset.mems' +if [ ! -e /sys/fs/cgroup/cpu/mckrt ]; then + mkdir /sys/fs/cgroup/cpu/mckrt + echo 950000 > /sys/fs/cgroup/cpu/mckrt/cpu.rt_runtime_us +fi +sudo bash -c "echo $PPID > /sys/fs/cgroup/cpu/mckrt/tasks" + +第2の計算ノード(progress threadでtofu getする)で次のコマンドを実行する。 +sudo ./ctrl 1 1 1 0 0 0 1 1 1 +sudo /bin/mcexec --enable-uti ./uti_perf -a 0,0,0,0,0,0 -r -f 1 -n 1 -l $((4*1024*1024)) -v +... +do_recv: Measure the reaction delay, Ready + +"do_recv: Measure the reaction delay, Ready" を確認したあと、 +第1の計算ノード(第2の計算ノードに受信を指示する)で次のコマンドを実行する。 +sudo ./ctrl 1 1 1 0 0 0 1 1 1 +sudo ./uti_perf -a 0,0,0,1,0,0 -f 1 -n 1 -l $((4*1024*1024)) -v + +オプション +========== + +(1) ctrl + +tofuサブネットを設定する。 +サブネットの意味は以下のとおり。 + +N: 各軸のシステムサイズ (1~32) +S: サブネット内での先頭座標(0~N-1) +L: サブネット内でのノード数(0~N)、0を指定するとネットワーク分割なし + +例えば、tofu座標が 0,0,0,0,0,0 と 0,0,0,1,0,0 の場合は次のように指定する。 +sudo ./ctrl 1 1 1 0 0 0 1 1 1 + + +(2) uti_perf + +progress threadを用いたtofu get通信速度を計測する。 +オプションは以下のとおり。 + +-a ,,,,, + 送信/受信相手のtofu座標を指定する。 + +-d , --d1= + progress threadの反応遅延測定時、プロトコル遅延として用いる時間を + 10ns単位で指定する。 + +-t none, --thread=none + progress threadを生成せずに tofu get通信を実行する。 + +-r + プログラムを受信モードで実行する。未指定時は送信モードになる。 + + -f + 生成するプロセス数を指定する。 (1~48、既定値は1) + 2以上の場合、tofu get通信を行うのは1プロセスのみで + ほかはprogress threadの生成のみを行う。 + + -n + 反応遅延またはプロトコル遅延の測定回数を指定する。 (既定値は10) + +-l + tofu get通信するデータサイズ(byte)を指定する。 + (64 byte ~ 16*1024*1024 - 256 byte、既定値は 16*1024*1024 - 256 byte) + +-v + デバッグ出力を有効にする。 + +--sendusleep= + 送信モードで測定毎に us (usec) だけ待ち合わせる。 + +--sendfifo + 送信モードでプロセスのスケジューリングポリシーを SCHED_FIFOにする。 + +--dummymode1 + tofu get通信を行わない progress threadを測定完了まで sleepさせる。 + +--thrprio= + progress threadの優先度を指定する。 (-20 ~ 19、既定値は10) + +--thrfifo + progress threadのスケジューリングポリシーを SCHED_FIFOにする。 + +--protocol + プロトコル遅延を測定する。 + "-f 1 -t none" オプション指定と同じ。 + +--ctrlretry= + tofu get通信フラグやスレッド間フラグの確認をリトライする回数を指定する。 + (既定値は10) + +--recvusleep= + progress threadの受信完了を確認する間隔 (usec) を指定する。 (既定値は0) diff --git a/test/uti/tofu/include/tof_test.h b/test/uti/tofu/include/tof_test.h new file mode 100644 index 00000000..574d3ed7 --- /dev/null +++ b/test/uti/tofu/include/tof_test.h @@ -0,0 +1,236 @@ +/* tof_test.h COPYRIGHT FUJITSU LIMITED 2021 */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tof_uapi.h" + +#define ST_RDWR 0x0 +#define ST_RDONLY 0x1 +#define ST_LPG 0x2 + +#define mb() asm volatile("dmb ish" ::: "memory") +static inline void BRK(void) {asm volatile ("brk #0");} +#define TOF_EXIT() (printf("ERROR:errorno=%d:line%d\n", errno, __LINE__),fflush(stdout),BRK(),exit(1)) +#define TOF_NG(str, ...) printf("TOF_NG ##### line%d "str"\n", __LINE__, ##__VA_ARGS__); +#define TOF_OK(str, ...) printf("TOF_OK ##### line%d "str"\n", __LINE__, ##__VA_ARGS__); +#define MMAP(len) ({\ + void *buf; \ + buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, -1, 0); \ + if(buf == MAP_FAILED){TOF_EXIT();} /* printf("mmap(%d)=%p\n", len, buf); */ buf;}) +#define PROGRESS() (printf("PROGRESS:%d\n", __LINE__)) +#define MALLOC(len) ({\ + void *buf; \ + buf = malloc(len); \ + if(buf == NULL){ \ + TOF_EXIT(); \ + } \ + buf;}) + +#define IOCTL(fd, id, req) ({ \ + int res; \ + res = ioctl(fd, id, req); \ + if(res != 0){ \ + TOF_EXIT(); \ + } \ + res;}) + +enum { + TOF_ICC_TOQ_NOP, + TOF_ICC_TOQ_PUT, + TOF_ICC_TOQ_WRITE_PIGGYBACK_BUFFER, + TOF_ICC_TOQ_PUT_PIGGYBACK, + TOF_ICC_TOQ_GET, + TOF_ICC_TOQ_GETL, + TOF_ICC_TOQ_ATOMIC_READ_MODIFY_WRITE = 0xe, + TOF_ICC_TOQ_TRANSMIT_RAW_PACKET1 = 0x10, + TOF_ICC_TOQ_TRANSMIT_RAW_PACKET2, + TOF_ICC_TOQ_TRANSMIT_SYSTEM_PACKET1, + TOF_ICC_TOQ_TRANSMIT_SYSTEM_PACKET2, + + TOF_ICC_TOQ_NCOMMANDS, +}; + +enum { + TOF_ICC_MRQ_ATOMIC_READ_MODIFY_WRITE_HALFWAY_NOTICE = 0x1, + TOF_ICC_MRQ_ATOMIC_READ_MODIFY_WRITE_NOTICE, + TOF_ICC_MRQ_ATOMIC_READ_MODIFY_WRITE_REMOTE_ERROR, + TOF_ICC_MRQ_PUT_HALFWAY_NOTICE, + TOF_ICC_MRQ_PUT_LAST_HALFWAY_NOTICE, + TOF_ICC_MRQ_GET_HALFWAY_NOTICE, + TOF_ICC_MRQ_GET_LAST_HALFWAY_NOTICE, + TOF_ICC_MRQ_PUT_NOTICE, + TOF_ICC_MRQ_PUT_LAST_NOTICE, + TOF_ICC_MRQ_GET_NOTICE, + TOF_ICC_MRQ_GET_LAST_NOTICE, + TOF_ICC_MRQ_PUT_REMOTE_ERROR, + TOF_ICC_MRQ_PUT_LAST_REMOTE_ERROR, + TOF_ICC_MRQ_GET_REMOTE_ERROR, + TOF_ICC_MRQ_GET_LAST_REMOTE_ERROR, + + TOF_ICC_MRQ_NCOMMANDS, +}; + +struct tof_icc_cq_stag_offset { + uint64_t offset:40; + uint64_t stag:18; + uint64_t cqid:6; +}; + +struct tof_icc_toq_common_header1 { + uint8_t interrupt:1; + uint8_t res1:4; + uint8_t source_type:2; + uint8_t flip:1; + uint8_t command; + union { + uint8_t mtu; + struct { + uint8_t res:4; + uint8_t op:4; + } armw; + } mtuop; + uint8_t sps:4; + uint8_t pa:1; + uint8_t pb:2; + uint8_t pc:1; + uint8_t rx; + uint8_t ry; + uint8_t rz; + uint8_t ra:1; + uint8_t rb:2; + uint8_t rc:1; + uint8_t res3:1; + uint8_t ri:3; +}; + +struct tof_icc_toq_common_header2 { + uint8_t gap; + uint8_t s:1; + uint8_t r:1; + uint8_t q:1; + uint8_t p:1; + uint8_t res1:1; + uint8_t j:1; + uint8_t res2:2; + uint16_t edata; + union{ + struct { + uint32_t length:24; + uint32_t res:8; + } normal; + struct { + uint32_t length:6; + uint32_t res:26; + } piggyback; + } len; +}; + +struct tof_icc_toq_put { + struct tof_icc_toq_common_header1 head1; + struct tof_icc_toq_common_header2 head2; + struct tof_icc_cq_stag_offset remote; + struct tof_icc_cq_stag_offset local; +}; + +struct tof_icc_toq_get { + struct tof_icc_toq_common_header1 head1; + struct tof_icc_toq_common_header2 head2; + struct tof_icc_cq_stag_offset remote; + struct tof_icc_cq_stag_offset local; +}; + +struct tof_icc_tcq_descriptor { + uint8_t res1:5; + uint8_t counter_unmatch:1; + uint8_t res2:1; + uint8_t flip:1; + uint8_t rcode; + uint8_t res3[2]; + union{ + struct { + uint32_t length:24; + uint32_t res:8; + } normal; + struct { + uint32_t length:6; + uint32_t res:26; + } piggyback; + } len; +}; + +struct tof_icc_mrq_common_header1 { + uint8_t res1:7; + uint8_t flip:1; + uint8_t id; + uint8_t rcode; + uint8_t res2:4; + uint8_t pa:1; + uint8_t pb:2; + uint8_t pc:1; + uint8_t x; + uint8_t y; + uint8_t z; + uint8_t a:1; + uint8_t b:2; + uint8_t c:1; + uint8_t res3:1; + uint8_t i:3; +}; + +struct tof_icc_mrq_common_header2 { + uint8_t res1; + uint8_t res2:4; + uint8_t initial:1; + uint8_t res3:3; + uint16_t edata; + union { + struct { + uint32_t length:11; + uint32_t res:21; + } normal; + struct { + uint32_t op:4; + uint32_t res:28; + } armw; + } lenop; +}; + +struct tof_icc_mrq_descriptor { + struct tof_icc_mrq_common_header1 head1; + struct tof_icc_mrq_common_header2 head2; + struct tof_icc_cq_stag_offset cso1; + struct tof_icc_cq_stag_offset cso2; +}; + +static inline void get_position(struct tof_addr *addr){ + int fd; + char buf[256]; + ssize_t res; + + fd = open("/proc/tofu/position", O_RDWR); + if(fd < 0){ + TOF_EXIT(); + } + res = read(fd, buf, 256); + if(res <= 0){ + TOF_EXIT(); + } + buf[res] = '0'; + if(sscanf(buf, "%d %d %d %d %d %d", &addr->x, &addr->y, &addr->z, &addr->a, &addr->b, &addr->c) != 6){ + TOF_EXIT(); + } + + close(fd); +} + +static inline uint64_t get_timestamp(void){ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000 + (uint64_t)ts.tv_nsec / 1000; +} diff --git a/test/uti/tofu/include/tof_uapi.h b/test/uti/tofu/include/tof_uapi.h new file mode 100644 index 00000000..1540d2d2 --- /dev/null +++ b/test/uti/tofu/include/tof_uapi.h @@ -0,0 +1,345 @@ +/* tof_uapi.h COPYRIGHT FUJITSU LIMITED 2021 */ +#ifndef _TOF_UAPI_H_ +#define _TOF_UAPI_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#include +#include +#include +#endif + +enum tof_sig_errno_cq { + TOF_TOQ_DIRECT_DESCRIPTOR_EXCEPTION, + TOF_TOQ_SOURCE_TYPE_EXCEPTION, + TOF_MRQ_OVERFLOW, +}; + +enum tof_sig_errno_bg { + TOF_NODE_ADDRESS_UNMATCH, + TOF_BSEQ_UNMATCH, + TOF_SIGNAL_STATE_ERROR, + TOF_ERROR_SYNCHRONIZATION_ACKNOWLEDGE, +}; + +#define TOF_UAPI_VERSION 0x2a00 + +struct tof_init_cq { + uint16_t version; + uint8_t session_mode; + uint8_t toq_size; + uint8_t mrq_size; + uint8_t num_stag; + uint8_t tcq_cinj; + uint8_t mrq_cinj; + void *toq_mem; + void *tcq_mem; + void *mrq_mem; +}; + +struct tof_alloc_stag { + uint32_t flags; + int stag; + uint64_t offset; + void *va; + uint64_t len; +}; + +struct tof_free_stags { + uint16_t num; + int *stags; +}; + +struct tof_addr { + uint8_t pa; + uint8_t pb; + uint8_t pc; + uint8_t x; + uint8_t y; + uint8_t z; + uint8_t a; + uint8_t b; + uint8_t c; +}; + +struct tof_set_bg { + int tni; + int gate; + int source_lgate; + struct tof_addr source_raddr; + int source_rtni; + int source_rgate; + int dest_lgate; + struct tof_addr dest_raddr; + int dest_rtni; + int dest_rgate; +}; + +struct tof_enable_bch { + void *addr; + int bseq; + int num; + struct tof_set_bg *bgs; +}; + +struct tof_set_subnet { + int res0; + int res1; + uint8_t nx; + uint8_t sx; + uint8_t lx; + uint8_t ny; + uint8_t sy; + uint8_t ly; + uint8_t nz; + uint8_t sz; + uint8_t lz; +}; + +struct tof_reg_user { + uid_t uid; + uint32_t gpid; + struct tof_set_subnet subnet; + uint64_t *cqmask; + uint64_t *bgmask; +}; + +struct tof_notify_linkdown { + int num; + struct { + uint8_t x; + uint8_t y; + uint8_t z; + uint8_t a; + uint8_t b; + uint8_t c; + uint16_t ports; + } *items; +}; + +struct tof_get_port_stat { + int port_no; + uint64_t mask; + uint64_t pa[31]; +}; + +struct tof_get_cq_stat { + int tni; + int cqid; + uint64_t txbyte; + uint64_t rxbyte; +}; + +struct tof_load_register { + uint64_t pa; + uint64_t len; + void *buf; +}; + +struct tof_load_resource { + uint64_t rsc_id; + uint64_t offset; + uint64_t len; + void *buf; +}; + +union tof_trans_table_bitfield { + struct { + uint64_t start:36; + uint64_t len:27; + uint64_t ps_code:1; + } bits; + uint64_t atomic; +}; + +struct tof_trans_table { + union tof_trans_table_bitfield steering; + union tof_trans_table_bitfield mbpt; +}; + +void tof_utofu_set_linkdown_callback(void (*callback)(int, const void *)); +void tof_utofu_unset_linkdown_callback(void); + +#define TOF_MMAP_CQ_REGISTER 0 +#ifdef __KERNEL__ +#define TOF_MMAP_CQ_TRANSTABLE (PAGE_SIZE) +#else +#define TOF_MMAP_CQ_TRANSTABLE (sysconf(_SC_PAGESIZE)) +#endif +#define TOF_MMAP_BCH_REGISTER 0 +#define TOF_MMAP_XB_STQ 0 + +#define TOF_ST_RDWR 0x0 +#define TOF_ST_RDONLY 0x1 +#define TOF_ST_LPG 0x2 + +#define TOF_STAG_TRANS_PS_CODE_64KB 0 +#define TOF_STAG_TRANS_PS_CODE_2MB 1 + +#define TOF_IOC_MAGIC 'd' +#define TOF_IOCTL_INIT_CQ _IOWR(TOF_IOC_MAGIC, 0, long) +#define TOF_IOCTL_ALLOC_STAG _IOWR(TOF_IOC_MAGIC, 1, long) +#define TOF_IOCTL_FREE_STAGS _IOWR(TOF_IOC_MAGIC, 2, long) +#define TOF_IOCTL_ENABLE_BCH _IOWR(TOF_IOC_MAGIC, 3, long) +#define TOF_IOCTL_DISABLE_BCH _IOWR(TOF_IOC_MAGIC, 4, long) +#define TOF_IOCTL_SET_RT_SIGNAL _IOWR(TOF_IOC_MAGIC, 5, long) +#define TOF_IOCTL_SET_SUBNET _IOWR(TOF_IOC_MAGIC, 6, long) +#define TOF_IOCTL_REG_USER _IOWR(TOF_IOC_MAGIC, 7, long) +#define TOF_IOCTL_NOTIFY_LINKDOWN _IOWR(TOF_IOC_MAGIC, 8, long) +#define TOF_IOCTL_GET_PORT_STAT _IOWR(TOF_IOC_MAGIC, 9, long) +#define TOF_IOCTL_GET_CQ_STAT _IOWR(TOF_IOC_MAGIC, 10, long) +#define TOF_IOCTL_LOAD_REGISTER _IOWR(TOF_IOC_MAGIC, 11, long) +#define TOF_IOCTL_LOAD_RESOURCE _IOWR(TOF_IOC_MAGIC, 12, long) + +#ifndef __KERNEL__ +#define TOF_INIT_CQ TOF_IOCTL_INIT_CQ +#define TOF_ALLOC_STAG TOF_IOCTL_ALLOC_STAG +#define TOF_FREE_STAGS TOF_IOCTL_FREE_STAGS +#define TOF_ENABLE_BCH TOF_IOCTL_ENABLE_BCH +#define TOF_DISABLE_BCH TOF_IOCTL_DISABLE_BCH +#define TOF_SET_RT_SIGNAL TOF_IOCTL_SET_RT_SIGNAL +#define TOF_SET_SUBNET TOF_IOCTL_SET_SUBNET +#define TOF_REG_USER TOF_IOCTL_REG_USER +#define TOF_NOTIFY_LINKDOWN TOF_IOCTL_NOTIFY_LINKDOWN +#define TOF_GET_PORT_STAT TOF_IOCTL_GET_PORT_STAT +#define TOF_GET_CQ_STAT TOF_IOCTL_GET_CQ_STAT +#define TOF_LOAD_REGISTER TOF_IOCTL_LOAD_REGISTER +#define TOF_LOAD_RESOURCE TOF_IOCTL_LOAD_RESOURCE +#endif + +enum { + /* TOQ (0 - 71) */ + TOF_RSC_TNI0_TOQ0 = 0, TOF_RSC_TNI0_TOQ1, TOF_RSC_TNI0_TOQ2, TOF_RSC_TNI0_TOQ3, + TOF_RSC_TNI0_TOQ4, TOF_RSC_TNI0_TOQ5, TOF_RSC_TNI0_TOQ6, TOF_RSC_TNI0_TOQ7, + TOF_RSC_TNI0_TOQ8, TOF_RSC_TNI0_TOQ9, TOF_RSC_TNI0_TOQ10, TOF_RSC_TNI0_TOQ11, + TOF_RSC_TNI1_TOQ0, TOF_RSC_TNI1_TOQ1, TOF_RSC_TNI1_TOQ2, TOF_RSC_TNI1_TOQ3, + TOF_RSC_TNI1_TOQ4, TOF_RSC_TNI1_TOQ5, TOF_RSC_TNI1_TOQ6, TOF_RSC_TNI1_TOQ7, + TOF_RSC_TNI1_TOQ8, TOF_RSC_TNI1_TOQ9, TOF_RSC_TNI1_TOQ10, TOF_RSC_TNI1_TOQ11, + TOF_RSC_TNI2_TOQ0, TOF_RSC_TNI2_TOQ1, TOF_RSC_TNI2_TOQ2, TOF_RSC_TNI2_TOQ3, + TOF_RSC_TNI2_TOQ4, TOF_RSC_TNI2_TOQ5, TOF_RSC_TNI2_TOQ6, TOF_RSC_TNI2_TOQ7, + TOF_RSC_TNI2_TOQ8, TOF_RSC_TNI2_TOQ9, TOF_RSC_TNI2_TOQ10, TOF_RSC_TNI2_TOQ11, + TOF_RSC_TNI3_TOQ0, TOF_RSC_TNI3_TOQ1, TOF_RSC_TNI3_TOQ2, TOF_RSC_TNI3_TOQ3, + TOF_RSC_TNI3_TOQ4, TOF_RSC_TNI3_TOQ5, TOF_RSC_TNI3_TOQ6, TOF_RSC_TNI3_TOQ7, + TOF_RSC_TNI3_TOQ8, TOF_RSC_TNI3_TOQ9, TOF_RSC_TNI3_TOQ10, TOF_RSC_TNI3_TOQ11, + TOF_RSC_TNI4_TOQ0, TOF_RSC_TNI4_TOQ1, TOF_RSC_TNI4_TOQ2, TOF_RSC_TNI4_TOQ3, + TOF_RSC_TNI4_TOQ4, TOF_RSC_TNI4_TOQ5, TOF_RSC_TNI4_TOQ6, TOF_RSC_TNI4_TOQ7, + TOF_RSC_TNI4_TOQ8, TOF_RSC_TNI4_TOQ9, TOF_RSC_TNI4_TOQ10, TOF_RSC_TNI4_TOQ11, + TOF_RSC_TNI5_TOQ0, TOF_RSC_TNI5_TOQ1, TOF_RSC_TNI5_TOQ2, TOF_RSC_TNI5_TOQ3, + TOF_RSC_TNI5_TOQ4, TOF_RSC_TNI5_TOQ5, TOF_RSC_TNI5_TOQ6, TOF_RSC_TNI5_TOQ7, + TOF_RSC_TNI5_TOQ8, TOF_RSC_TNI5_TOQ9, TOF_RSC_TNI5_TOQ10, TOF_RSC_TNI5_TOQ11, + + /* TOQ (72 - 143) */ + TOF_RSC_TNI0_TCQ0, TOF_RSC_TNI0_TCQ1, TOF_RSC_TNI0_TCQ2, TOF_RSC_TNI0_TCQ3, + TOF_RSC_TNI0_TCQ4, TOF_RSC_TNI0_TCQ5, TOF_RSC_TNI0_TCQ6, TOF_RSC_TNI0_TCQ7, + TOF_RSC_TNI0_TCQ8, TOF_RSC_TNI0_TCQ9, TOF_RSC_TNI0_TCQ10, TOF_RSC_TNI0_TCQ11, + TOF_RSC_TNI1_TCQ0, TOF_RSC_TNI1_TCQ1, TOF_RSC_TNI1_TCQ2, TOF_RSC_TNI1_TCQ3, + TOF_RSC_TNI1_TCQ4, TOF_RSC_TNI1_TCQ5, TOF_RSC_TNI1_TCQ6, TOF_RSC_TNI1_TCQ7, + TOF_RSC_TNI1_TCQ8, TOF_RSC_TNI1_TCQ9, TOF_RSC_TNI1_TCQ10, TOF_RSC_TNI1_TCQ11, + TOF_RSC_TNI2_TCQ0, TOF_RSC_TNI2_TCQ1, TOF_RSC_TNI2_TCQ2, TOF_RSC_TNI2_TCQ3, + TOF_RSC_TNI2_TCQ4, TOF_RSC_TNI2_TCQ5, TOF_RSC_TNI2_TCQ6, TOF_RSC_TNI2_TCQ7, + TOF_RSC_TNI2_TCQ8, TOF_RSC_TNI2_TCQ9, TOF_RSC_TNI2_TCQ10, TOF_RSC_TNI2_TCQ11, + TOF_RSC_TNI3_TCQ0, TOF_RSC_TNI3_TCQ1, TOF_RSC_TNI3_TCQ2, TOF_RSC_TNI3_TCQ3, + TOF_RSC_TNI3_TCQ4, TOF_RSC_TNI3_TCQ5, TOF_RSC_TNI3_TCQ6, TOF_RSC_TNI3_TCQ7, + TOF_RSC_TNI3_TCQ8, TOF_RSC_TNI3_TCQ9, TOF_RSC_TNI3_TCQ10, TOF_RSC_TNI3_TCQ11, + TOF_RSC_TNI4_TCQ0, TOF_RSC_TNI4_TCQ1, TOF_RSC_TNI4_TCQ2, TOF_RSC_TNI4_TCQ3, + TOF_RSC_TNI4_TCQ4, TOF_RSC_TNI4_TCQ5, TOF_RSC_TNI4_TCQ6, TOF_RSC_TNI4_TCQ7, + TOF_RSC_TNI4_TCQ8, TOF_RSC_TNI4_TCQ9, TOF_RSC_TNI4_TCQ10, TOF_RSC_TNI4_TCQ11, + TOF_RSC_TNI5_TCQ0, TOF_RSC_TNI5_TCQ1, TOF_RSC_TNI5_TCQ2, TOF_RSC_TNI5_TCQ3, + TOF_RSC_TNI5_TCQ4, TOF_RSC_TNI5_TCQ5, TOF_RSC_TNI5_TCQ6, TOF_RSC_TNI5_TCQ7, + TOF_RSC_TNI5_TCQ8, TOF_RSC_TNI5_TCQ9, TOF_RSC_TNI5_TCQ10, TOF_RSC_TNI5_TCQ11, + + /* MRQ (144 - 215) */ + TOF_RSC_TNI0_MRQ0, TOF_RSC_TNI0_MRQ1, TOF_RSC_TNI0_MRQ2, TOF_RSC_TNI0_MRQ3, + TOF_RSC_TNI0_MRQ4, TOF_RSC_TNI0_MRQ5, TOF_RSC_TNI0_MRQ6, TOF_RSC_TNI0_MRQ7, + TOF_RSC_TNI0_MRQ8, TOF_RSC_TNI0_MRQ9, TOF_RSC_TNI0_MRQ10, TOF_RSC_TNI0_MRQ11, + TOF_RSC_TNI1_MRQ0, TOF_RSC_TNI1_MRQ1, TOF_RSC_TNI1_MRQ2, TOF_RSC_TNI1_MRQ3, + TOF_RSC_TNI1_MRQ4, TOF_RSC_TNI1_MRQ5, TOF_RSC_TNI1_MRQ6, TOF_RSC_TNI1_MRQ7, + TOF_RSC_TNI1_MRQ8, TOF_RSC_TNI1_MRQ9, TOF_RSC_TNI1_MRQ10, TOF_RSC_TNI1_MRQ11, + TOF_RSC_TNI2_MRQ0, TOF_RSC_TNI2_MRQ1, TOF_RSC_TNI2_MRQ2, TOF_RSC_TNI2_MRQ3, + TOF_RSC_TNI2_MRQ4, TOF_RSC_TNI2_MRQ5, TOF_RSC_TNI2_MRQ6, TOF_RSC_TNI2_MRQ7, + TOF_RSC_TNI2_MRQ8, TOF_RSC_TNI2_MRQ9, TOF_RSC_TNI2_MRQ10, TOF_RSC_TNI2_MRQ11, + TOF_RSC_TNI3_MRQ0, TOF_RSC_TNI3_MRQ1, TOF_RSC_TNI3_MRQ2, TOF_RSC_TNI3_MRQ3, + TOF_RSC_TNI3_MRQ4, TOF_RSC_TNI3_MRQ5, TOF_RSC_TNI3_MRQ6, TOF_RSC_TNI3_MRQ7, + TOF_RSC_TNI3_MRQ8, TOF_RSC_TNI3_MRQ9, TOF_RSC_TNI3_MRQ10, TOF_RSC_TNI3_MRQ11, + TOF_RSC_TNI4_MRQ0, TOF_RSC_TNI4_MRQ1, TOF_RSC_TNI4_MRQ2, TOF_RSC_TNI4_MRQ3, + TOF_RSC_TNI4_MRQ4, TOF_RSC_TNI4_MRQ5, TOF_RSC_TNI4_MRQ6, TOF_RSC_TNI4_MRQ7, + TOF_RSC_TNI4_MRQ8, TOF_RSC_TNI4_MRQ9, TOF_RSC_TNI4_MRQ10, TOF_RSC_TNI4_MRQ11, + TOF_RSC_TNI5_MRQ0, TOF_RSC_TNI5_MRQ1, TOF_RSC_TNI5_MRQ2, TOF_RSC_TNI5_MRQ3, + TOF_RSC_TNI5_MRQ4, TOF_RSC_TNI5_MRQ5, TOF_RSC_TNI5_MRQ6, TOF_RSC_TNI5_MRQ7, + TOF_RSC_TNI5_MRQ8, TOF_RSC_TNI5_MRQ9, TOF_RSC_TNI5_MRQ10, TOF_RSC_TNI5_MRQ11, + + /* PBQ (216 - 221) */ + TOF_RSC_TNI0_PBQ, TOF_RSC_TNI1_PBQ, TOF_RSC_TNI2_PBQ, TOF_RSC_TNI3_PBQ, + TOF_RSC_TNI4_PBQ, TOF_RSC_TNI5_PBQ, + + /* PRQ (222 - 227) */ + TOF_RSC_TNI0_PRQ, TOF_RSC_TNI1_PRQ, TOF_RSC_TNI2_PRQ, TOF_RSC_TNI3_PRQ, + TOF_RSC_TNI4_PRQ, TOF_RSC_TNI5_PRQ, + + /* STEERINGTABLE (228 - 299) */ + TOF_RSC_TNI0_STEERINGTABLE0, TOF_RSC_TNI0_STEERINGTABLE1, TOF_RSC_TNI0_STEERINGTABLE2, + TOF_RSC_TNI0_STEERINGTABLE3, TOF_RSC_TNI0_STEERINGTABLE4, TOF_RSC_TNI0_STEERINGTABLE5, + TOF_RSC_TNI0_STEERINGTABLE6, TOF_RSC_TNI0_STEERINGTABLE7, TOF_RSC_TNI0_STEERINGTABLE8, + TOF_RSC_TNI0_STEERINGTABLE9, TOF_RSC_TNI0_STEERINGTABLE10, TOF_RSC_TNI0_STEERINGTABLE11, + TOF_RSC_TNI1_STEERINGTABLE0, TOF_RSC_TNI1_STEERINGTABLE1, TOF_RSC_TNI1_STEERINGTABLE2, + TOF_RSC_TNI1_STEERINGTABLE3, TOF_RSC_TNI1_STEERINGTABLE4, TOF_RSC_TNI1_STEERINGTABLE5, + TOF_RSC_TNI1_STEERINGTABLE6, TOF_RSC_TNI1_STEERINGTABLE7, TOF_RSC_TNI1_STEERINGTABLE8, + TOF_RSC_TNI1_STEERINGTABLE9, TOF_RSC_TNI1_STEERINGTABLE10, TOF_RSC_TNI1_STEERINGTABLE11, + TOF_RSC_TNI2_STEERINGTABLE0, TOF_RSC_TNI2_STEERINGTABLE1, TOF_RSC_TNI2_STEERINGTABLE2, + TOF_RSC_TNI2_STEERINGTABLE3, TOF_RSC_TNI2_STEERINGTABLE4, TOF_RSC_TNI2_STEERINGTABLE5, + TOF_RSC_TNI2_STEERINGTABLE6, TOF_RSC_TNI2_STEERINGTABLE7, TOF_RSC_TNI2_STEERINGTABLE8, + TOF_RSC_TNI2_STEERINGTABLE9, TOF_RSC_TNI2_STEERINGTABLE10, TOF_RSC_TNI2_STEERINGTABLE11, + TOF_RSC_TNI3_STEERINGTABLE0, TOF_RSC_TNI3_STEERINGTABLE1, TOF_RSC_TNI3_STEERINGTABLE2, + TOF_RSC_TNI3_STEERINGTABLE3, TOF_RSC_TNI3_STEERINGTABLE4, TOF_RSC_TNI3_STEERINGTABLE5, + TOF_RSC_TNI3_STEERINGTABLE6, TOF_RSC_TNI3_STEERINGTABLE7, TOF_RSC_TNI3_STEERINGTABLE8, + TOF_RSC_TNI3_STEERINGTABLE9, TOF_RSC_TNI3_STEERINGTABLE10, TOF_RSC_TNI3_STEERINGTABLE11, + TOF_RSC_TNI4_STEERINGTABLE0, TOF_RSC_TNI4_STEERINGTABLE1, TOF_RSC_TNI4_STEERINGTABLE2, + TOF_RSC_TNI4_STEERINGTABLE3, TOF_RSC_TNI4_STEERINGTABLE4, TOF_RSC_TNI4_STEERINGTABLE5, + TOF_RSC_TNI4_STEERINGTABLE6, TOF_RSC_TNI4_STEERINGTABLE7, TOF_RSC_TNI4_STEERINGTABLE8, + TOF_RSC_TNI4_STEERINGTABLE9, TOF_RSC_TNI4_STEERINGTABLE10, TOF_RSC_TNI4_STEERINGTABLE11, + TOF_RSC_TNI5_STEERINGTABLE3, TOF_RSC_TNI5_STEERINGTABLE4, TOF_RSC_TNI5_STEERINGTABLE5, + TOF_RSC_TNI5_STEERINGTABLE6, TOF_RSC_TNI5_STEERINGTABLE7, TOF_RSC_TNI5_STEERINGTABLE8, + TOF_RSC_TNI5_STEERINGTABLE9, TOF_RSC_TNI5_STEERINGTABLE10, TOF_RSC_TNI5_STEERINGTABLE11, + + /* MBTABLE (300 - 371) */ + TOF_RSC_TNI0_MBTABLE0, TOF_RSC_TNI0_MBTABLE1, TOF_RSC_TNI0_MBTABLE2, + TOF_RSC_TNI0_MBTABLE3, TOF_RSC_TNI0_MBTABLE4, TOF_RSC_TNI0_MBTABLE5, + TOF_RSC_TNI0_MBTABLE6, TOF_RSC_TNI0_MBTABLE7, TOF_RSC_TNI0_MBTABLE8, + TOF_RSC_TNI0_MBTABLE9, TOF_RSC_TNI0_MBTABLE10, TOF_RSC_TNI0_MBTABLE11, + TOF_RSC_TNI1_MBTABLE0, TOF_RSC_TNI1_MBTABLE1, TOF_RSC_TNI1_MBTABLE2, + TOF_RSC_TNI1_MBTABLE3, TOF_RSC_TNI1_MBTABLE4, TOF_RSC_TNI1_MBTABLE5, + TOF_RSC_TNI1_MBTABLE6, TOF_RSC_TNI1_MBTABLE7, TOF_RSC_TNI1_MBTABLE8, + TOF_RSC_TNI1_MBTABLE9, TOF_RSC_TNI1_MBTABLE10, TOF_RSC_TNI1_MBTABLE11, + TOF_RSC_TNI2_MBTABLE0, TOF_RSC_TNI2_MBTABLE1, TOF_RSC_TNI2_MBTABLE2, + TOF_RSC_TNI2_MBTABLE3, TOF_RSC_TNI2_MBTABLE4, TOF_RSC_TNI2_MBTABLE5, + TOF_RSC_TNI2_MBTABLE6, TOF_RSC_TNI2_MBTABLE7, TOF_RSC_TNI2_MBTABLE8, + TOF_RSC_TNI2_MBTABLE9, TOF_RSC_TNI2_MBTABLE10, TOF_RSC_TNI2_MBTABLE11, + TOF_RSC_TNI3_MBTABLE0, TOF_RSC_TNI3_MBTABLE1, TOF_RSC_TNI3_MBTABLE2, + TOF_RSC_TNI3_MBTABLE3, TOF_RSC_TNI3_MBTABLE4, TOF_RSC_TNI3_MBTABLE5, + TOF_RSC_TNI3_MBTABLE6, TOF_RSC_TNI3_MBTABLE7, TOF_RSC_TNI3_MBTABLE8, + TOF_RSC_TNI3_MBTABLE9, TOF_RSC_TNI3_MBTABLE10, TOF_RSC_TNI3_MBTABLE11, + TOF_RSC_TNI4_MBTABLE0, TOF_RSC_TNI4_MBTABLE1, TOF_RSC_TNI4_MBTABLE2, + TOF_RSC_TNI4_MBTABLE3, TOF_RSC_TNI4_MBTABLE4, TOF_RSC_TNI4_MBTABLE5, + TOF_RSC_TNI4_MBTABLE6, TOF_RSC_TNI4_MBTABLE7, TOF_RSC_TNI4_MBTABLE8, + TOF_RSC_TNI4_MBTABLE9, TOF_RSC_TNI4_MBTABLE10, TOF_RSC_TNI4_MBTABLE11, + TOF_RSC_TNI5_MBTABLE0, TOF_RSC_TNI5_MBTABLE1, TOF_RSC_TNI5_MBTABLE2, + TOF_RSC_TNI5_MBTABLE3, TOF_RSC_TNI5_MBTABLE4, TOF_RSC_TNI5_MBTABLE5, + TOF_RSC_TNI5_MBTABLE6, TOF_RSC_TNI5_MBTABLE7, TOF_RSC_TNI5_MBTABLE8, + TOF_RSC_TNI5_MBTABLE9, TOF_RSC_TNI5_MBTABLE10, TOF_RSC_TNI5_MBTABLE11, + + TOF_RSC_NUM /* 372 */ +}; +#define TOF_RSC_TOQ(TNI, CQID) (TOF_RSC_TNI0_TOQ0 + (TNI * 12) + CQID) +#define TOF_RSC_TCQ(TNI, CQID) (TOF_RSC_TNI0_TCQ0 + (TNI * 12) + CQID) +#define TOF_RSC_MRQ(TNI, CQID) (TOF_RSC_TNI0_MRQ0 + (TNI * 12) + CQID) +#define TOF_RSC_PBQ(TNI) (TOF_RSC_TNI0_PBQ + TNI) +#define TOF_RSC_PRQ(TNI) (TOF_RSC_TNI0_PRQ + TNI) +#define TOF_RSC_STT(TNI, CQID) (TOF_RSC_TNI0_STEERINGTABLE0 + (TNI * 12) + CQID) +#define TOF_RSC_MBT(TNI, CQID) (TOF_RSC_TNI0_MBTABLE0 + (TNI * 12) + CQID) + +#endif + +/* vim: set noet ts=8 sw=8 sts=0 tw=0 : */ + diff --git a/test/uti/tofu/init.sh b/test/uti/tofu/init.sh new file mode 100755 index 00000000..f12d83f8 --- /dev/null +++ b/test/uti/tofu/init.sh @@ -0,0 +1,39 @@ +#!/usr/bin/bash + +SCRIPT_PATH=$(readlink -m "${BASH_SOURCE[0]}") +TEST_HOME="${SCRIPT_PATH%/*/*/*}" + +# stop TCS +sudo systemctl stop pxkrm-plugin-mckernel krm-iptables +sudo systemctl stop pxmonitor_pre.service pxmonitor_slaved.service pxnrd.service pxeventd.service pxpled.service paclmgr_notice.service pxkrm.service pxpwrd.service +sudo systemctl stop FJSVxosmck FJSVxoshpcpwr-plugin-mckernel pxpwrm_perm_mck.service +sudo rm -f /dev/shm/rml* + +while true; do + sudo systemctl status pxkrm-plugin-mckernel krm-iptables pxmonitor_slaved pxnrd pxpled paclmgr_notice pxkrm pxpwrd FJSVxosmck FJSVxoshpcpwr-plugin-mckernel pxpwrm_perm_mck | awk '/Active/ {print $2}' | grep -w active + (( $? != 0 )) && break +done + +# mcstop +if [[ "$1" == "mck" ]]; then + MCREBOOT=0 + . $TEST_HOME/common.sh +fi + +# cgroup +sudo bash -c 'echo "0,1,12-59" > /sys/fs/cgroup/cpuset/system.slice/cpuset.cpus' +sudo bash -c 'echo "0-7" > /sys/fs/cgroup/cpuset/system.slice/cpuset.mems' + +if [ ! -e /sys/fs/cgroup/cpu/mckrt ]; then + sudo mkdir /sys/fs/cgroup/cpu/mckrt + sudo bash -c 'echo 950000 > /sys/fs/cgroup/cpu/mckrt/cpu.rt_runtime_us' +fi +grandma=$(ps xao pid,ppid|awk '$1 == "'$PPID'" {print $2}') +sudo bash -c "echo $grandma > /sys/fs/cgroup/cpu/mckrt/tasks" + +# tofu +sudo ./ctrl 1 1 1 0 0 0 1 1 1 + +if [[ "$1" == "mck" ]]; then + mcreboot +fi diff --git a/test/uti/tofu/with_libuti/Makefile b/test/uti/tofu/with_libuti/Makefile new file mode 100644 index 00000000..3872ea1f --- /dev/null +++ b/test/uti/tofu/with_libuti/Makefile @@ -0,0 +1,20 @@ +# Makefile COPYRIGHT FUJITSU LIMITED 2021 + +CC = gcc +INC = -I../include -I/home/users/ea01/ea0105/aarch64/usr/include +LDFLAGS = -lpthread -L/home/users/ea01/ea0105/aarch64/usr/lib -luti -Wl,-rpath -Wl,/home/users/ea01/ea0105/aarch64/usr/lib +# CFLAGS = -g -Wall +CFLAGS = -g + +all: uti_perf ctrl + +ctrl: ctrl.c + $(CC) $(INC) $(LDFLAGS) $(CFLAGS) -o $@ $^ + +uti_perf: uti_perf.c + $(CC) $(INC) $(LDFLAGS) $(CFLAGS) -o $@ $^ + +.PHONY: clean +clean: + $(RM) -f uti_perf ctrl + diff --git a/test/uti/tofu/with_libuti/ctrl.c b/test/uti/tofu/with_libuti/ctrl.c new file mode 100644 index 00000000..7cce76bd --- /dev/null +++ b/test/uti/tofu/with_libuti/ctrl.c @@ -0,0 +1,74 @@ +/* ctrl COPYRIGHT FUJITSU LIMITED 2021 */ +#include +#include +#include + +#include "tof_uapi.h" +#include "tof_test.h" + +int main(int argc, char *argv[]){ + int ctl_fd; + int res; + struct tof_addr laddr; + struct tof_reg_user req; + uint64_t cqmask[6] = {0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff}; + uint64_t bgmask[6] = {0xfffffffffff,0xfffffffffff,0xfffffffffff, + 0xfffffffffff,0xfffffffffff,0xfffffffffff}; + + + if(argc != 1 && argc != 10){ + printf("usage: %s \n", argv[0]); + printf(" ex. %s 1 1 12 0 0 8 1 1 4\n", argv[0]); + exit(1); + } + get_position(&laddr); + + /* REG_USER*/ + req.uid = 0; /// root? + req.gpid = 23456; + req.subnet.nx = laddr.x+1; + req.subnet.ny = laddr.y+1; + req.subnet.nz = laddr.z+1; + req.subnet.sx = laddr.x; + req.subnet.sy = laddr.y; + req.subnet.sz = laddr.z; + req.subnet.lx = 1; + req.subnet.ly = 1; + req.subnet.lz = 1; + req.cqmask = (uint64_t *)&cqmask; + req.bgmask = (uint64_t *)&bgmask; + + if(argc == 10){ + req.subnet.nx = strtol(argv[1], NULL, 10); + req.subnet.ny = strtol(argv[2], NULL, 10); + req.subnet.nz = strtol(argv[3], NULL, 10); + req.subnet.sx = strtol(argv[4], NULL, 10); + req.subnet.sy = strtol(argv[5], NULL, 10); + req.subnet.sz = strtol(argv[6], NULL, 10); + req.subnet.lx = strtol(argv[7], NULL, 10); + req.subnet.ly = strtol(argv[8], NULL, 10); + req.subnet.lz = strtol(argv[9], NULL, 10); + } + ctl_fd = open("/proc/tofu/dev/control", O_CLOEXEC); + if(ctl_fd < 0){ + TOF_EXIT(); + } + +/* + res = ioctl(ctl_fd, TOF_IOCTL_SET_SUBNET, &req.subnet); + if(res != 0){ + TOF_EXIT(); + } +*/ + res = ioctl(ctl_fd, TOF_IOCTL_REG_USER, &req); + if(res != 0){ + TOF_EXIT(); + } + printf("subnet= %d %d %d %d %d %d %d %d %d\n", + req.subnet.nx, req.subnet.ny, req.subnet.nz, + req.subnet.sx, req.subnet.sy, req.subnet.sz, + req.subnet.lx, req.subnet.ly, req.subnet.lz); + printf("success:L%d\n", __LINE__); + return 0; +} + diff --git a/test/uti/tofu/with_libuti/uti_perf.c b/test/uti/tofu/with_libuti/uti_perf.c new file mode 100644 index 00000000..86ba0013 --- /dev/null +++ b/test/uti/tofu/with_libuti/uti_perf.c @@ -0,0 +1,1503 @@ +/* uti_perf COPYRIGHT FUJITSU LIMITED 2021 */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tof_uapi.h" +#include "tof_test.h" + +extern int __libc_allocate_rtsig (int __high); + +#define CTRL_MSGLEN (64) +#define DATA_MSGLEN (16 * 1024 * 1024 - 256) + +#define MSG_CREAR_TO_GET (0x58fca109U) +#define MSG_DONE (0x1105bf26U) +#define MSG_BARRIER (0x9c6108afU) +#define MSG_SEND_DELAY (0x61fb9044U) +#define MSG_INIT (0x065f8cbaU) + +#define RECV_PATTERN (0x00A0) +#define SEND_PATTERN (0x0050) + +/* param.mode bit */ +#define MODE_SEND (0x0000) +#define MODE_RECV (0x0001) +#define MODE_MASK (0x0001) + +#define THR_DEFAULT (0x0000) +#define THR_NONE (0x0002) /* do not create thread */ +#define THR_LCUY (0x0004) /* lock-check-unlock-yield */ +#define THR_MASK (0x0006) + +#define SEND_FIFO (0x00000010) +#define THR_FIFO (0x00000020) +#define DUMMY_MODE1 (0x00000040) + +#define OPT_RTSIG (0x01000000) +#define OPT_SYSCALL (0x02000000) +#define OPT_POLL (0x04000000) +#define OPT_CINJ (0x08000000) + +#define REMOTE() (param.remote) +#define LOCAL() (param.local) +#define IS_RECV() (((param.mode) & MODE_MASK) == MODE_RECV) +#define IS_SEND() (((param.mode) & MODE_MASK) == MODE_SEND) + +struct node_info { + int tni; + int cq; + int ctrl_in_stag; + int ctrl_out_stag; + int data_stag; + int bar_in_stag; + int bar_out_stag; + char clear_pattern; +}; + +struct tp_param { + int mode; + int delay; /* protocol delay, d1 */ + int count; /* number of measurements of delay */ + int length; /* data length */ + int forknum; /* number of processes */ + int send_usleep; /* usleep time for do_send */ + int recv_usleep; /* usleep time for do_recv */ + int thr_prio; /* progress thread priority */ + int ctrl_retry; /* ctrl retry count */ + struct tof_icc_toq_put *toq; + struct tof_icc_tcq_descriptor *tcq; + struct tof_icc_mrq_descriptor *mrq; + uint64_t *toq_reg; + uint64_t toq_cnt; + uint64_t mrq_cnt; + uint64_t bar_cnt; + struct tof_addr raddr; /* remote tofu address */ + void *ctrl_in_buf; + void *ctrl_out_buf; + void *data_buf; + void *bar_in_buf; + void *bar_out_buf; + + struct node_info local; /* constant data per node */ + struct node_info remote; +}; + +static int verbose = 0; +static struct tp_param param; + +static volatile int recv_complete = 0; +static volatile int dummy_complete = 0; + +static pthread_mutex_t mutex; +static pthread_cond_t cond; +static pthread_barrier_t bar; + +/* Fill constant parameters for the test */ +static int setup_tp_param (int proc) +{ + struct tof_addr laddr; + struct node_info *recv = IS_RECV() ? &LOCAL() : &REMOTE(); + struct node_info *send = IS_SEND() ? &LOCAL() : &REMOTE(); + + /* get local pos */ + /* TOF_EXIT(), if failed to get pos */ + get_position(&laddr); + + if ((laddr.x == param.raddr.x) && (laddr.a == param.raddr.a) && + (laddr.y == param.raddr.y) && (laddr.b == param.raddr.b) && + (laddr.z == param.raddr.z) && (laddr.c == param.raddr.c)) { + + /* same node, separate send/recv TNI */ + if (proc >= 11 || proc < 0) { + return -1; /* limit 11 process */ + } + recv->tni = 4; + recv->cq = proc; + send->tni = 5; + send->cq = proc; + + } else { + /* internode comm, use same TNI/CQ for send/recv */ + if (proc >= 48 || proc < 0) { + return -1; /* limit 48 process */ + } + send->tni = recv->tni = proc / 10 + 1; /* 1 - 5 */ + send->cq = recv->cq = proc % 10; /* 0 - 9 */ + } + + recv->ctrl_in_stag = recv->cq * 100 + recv->tni * 10 + 1; + recv->ctrl_out_stag = recv->cq * 100 + recv->tni * 10 + 2; + recv->data_stag = recv->cq * 100 + recv->tni * 10 + 3; + recv->bar_in_stag = recv->cq * 100 + recv->tni * 10 + 4; + recv->bar_out_stag = recv->cq * 100 + recv->tni * 10 + 5; + recv->clear_pattern = (char)(RECV_PATTERN + proc); + + send->ctrl_in_stag = send->cq * 100 + send->tni * 10 + 1; + send->ctrl_out_stag = send->cq * 100 + send->tni * 10 + 2; + send->data_stag = send->cq * 100 + send->tni * 10 + 3; + send->bar_in_stag = send->cq * 100 + send->tni * 10 + 4; + send->bar_out_stag = send->cq * 100 + send->tni * 10 + 5; + send->clear_pattern = (char)(SEND_PATTERN + proc); + + if (verbose) { + printf("mode : %s (proc=%d)\n", + (IS_RECV() ? "RECV" : "SEND"), proc); + printf("local : %d,%d,%d,%d,%d,%d tni=%d cq=%d\n", + laddr.x, laddr.y, laddr.z, laddr.a, laddr.b, laddr.c, + LOCAL().tni, LOCAL().cq); + printf("remote : %d,%d,%d,%d,%d,%d tni=%d cq=%d\n", + param.raddr.x, param.raddr.y, param.raddr.z, + param.raddr.a, param.raddr.b, param.raddr.c, + REMOTE().tni, REMOTE().cq); + } + return 0; +} + +/* create tofu device file name */ +static void create_tofu_device_name (char *file, int tni, int cq) +{ + strcpy(file, "/proc/tofu/dev/tni4cq0"); + file[18] = '0' + tni; + file[21] = '0' + cq; +} + +static int alloc_stag(int cq_fd, int msglen, int stag, void *buf) +{ + struct tof_alloc_stag alst; + int ret; + + alst.flags = 0; + alst.stag = stag; + alst.va = buf; + alst.len = msglen; + ret = ioctl(cq_fd, TOF_IOCTL_ALLOC_STAG, &alst); + if (ret != 0) { + perror("ioctl, TOF_IOCTL_ALLOC_STAG"); + return -1; + } + if (alst.offset != 0) { + fprintf(stderr, "%s: offset != 0\n", __FUNCTION__); + return -1; + } + + if (verbose) { + printf("va=%p len=%ld stag=%d offset=%ld\n", + alst.va, alst.len, alst.stag, alst.offset); + } + + return 0; +} + +int caused_signal_number = -1; + +void my_sig_action(int sig, siginfo_t *info, void *val){ + if(sig > 32){ + fprintf(stderr, "sig=%d si_int=0x%lx si_errno=%d si_code=%d\n", + sig, info->si_int, info->si_errno, info->si_code); + } + else { + fprintf(stderr, "sig=%d\n", sig); + } + fflush(stderr); + if(caused_signal_number == -1){ + caused_signal_number = sig; + } + else if(caused_signal_number != sig){ + fprintf(stderr, "2 different signal were sent: oldsig=%d newsig=%d\n", caused_signal_number, sig); + TOF_NG(); + TOF_EXIT(); + } +} + +void set_rtsignal(int fd){ + int sig; + int min, max; + int res; + struct sigaction sigact; + + min = SIGRTMIN; + max = SIGRTMAX; + sig = __libc_allocate_rtsig(1); + if(sig < min || sig > max){ + TOF_EXIT(); + } + res = ioctl(fd, TOF_SET_RT_SIGNAL, &sig); + if(res){ + TOF_EXIT(); + } + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = my_sig_action; + sigact.sa_flags = SA_SIGINFO; + sigemptyset(&sigact.sa_mask); + //sigaddset(&sigact.sa_mask, sig); + if(sigaction(sig, &sigact, NULL) != 0){ + TOF_EXIT(); + } + +// printf("setup signal\n"); +} + +void set_termsignal(void){ + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = my_sig_action; + //sigact.sa_flags = SA_SIGINFO; + sigemptyset(&sigact.sa_mask); + //sigaddset(&sigact.sa_mask, sig); + if(sigaction(SIGTERM, &sigact, NULL) != 0){ + TOF_EXIT(); + } +} + +static void chld_handler (int sig, siginfo_t *info, void *val) +{ + dummy_complete = 1; +} + +static void set_chldsignal (void) +{ + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = chld_handler; + sigemptyset(&sigact.sa_mask); + if(sigaction(SIGCHLD, &sigact, NULL) != 0){ + TOF_EXIT(); + } +} + +/* "0,1,2,3,4" -> {0,1,2,3,4} */ +static int str2int(const char *str, int *dst, int max) +{ + int i = 0; + char *s = (char *)str; + char *e; + + while (*s != '\0') { + dst[i] = (int)strtol(s, &e, 0); + + /* conversion failure */ + if (s == e) + break; + /* output buffer check */ + if (++i >= max) + break; + /* end of string */ + if (*e == '\0') + break; + /* get next pos */ + s = e + 1; + } + + return i; +} + +/* "0,1,2,3,4,5" -> struct tof_addr */ +static int str2pos(const char *str, struct tof_addr *addr) +{ + int dst[6]; + + if (str2int(str, dst, 6) == 6) { + addr->x = dst[0]; + addr->y = dst[1]; + addr->z = dst[2]; + addr->a = dst[3]; + addr->b = dst[4]; + addr->c = dst[5]; + return 0; + } else { + return 1; + } +} + +/* get 10ns (100MHz) timer counter */ +static inline unsigned long rdtsc_light(void) +{ + unsigned long x; + __asm__ __volatile__("isb \n\t" + "mrs %[output], cntvct_el0" + : [output]"=r"(x) + : + : "memory"); + return x; +} + +/* delay routine - begin */ +#define N_INIT 100000 +static double nspw = 0.0; /* 10 ns per work */ + +static inline void fixed_size_work (void) +{ + __asm__ __volatile__( + "mov x20, #0\n\t" + "1:\t" + "add x20, x20, #1\n\t" + "cmp x20, #99\n\t" + "b.le 1b\n\t" + : + : + : "x20", "cc", "memory"); +} + +static inline void bulk_fsw (unsigned long n) +{ + int j; + for(j = 0; j < n; j++) { + fixed_size_work(); + } +} + +static void fwq_init (void) +{ + unsigned long t1, t2; + t1 = rdtsc_light(); + bulk_fsw(N_INIT); + t2 = rdtsc_light(); + nspw = (double)(t2 - t1) / (double)N_INIT; +} + +static void fwq (long delay_10ns) +{ + if (delay_10ns >= 0) { + bulk_fsw(delay_10ns / nspw); + } +} +/* delay routine - end */ + +static int _getcpu (void) +{ + int cpu, ret; + + ret = syscall(SYS_getcpu, &cpu, NULL, NULL); + if (ret == -1) { + cpu = -1; + } + + return cpu; +} + +static int onmck (void) +{ + return (syscall(732) == -1 ? 0 : 1); +} + +/* + * tofu put/get + */ +static void tofu_putget ( + int command, int msglen, int mode, int lstag, int rstag) +{ + + struct tof_icc_toq_put *toq = param.toq; + uint64_t toq_cnt = param.toq_cnt; + + int mx , my , mz , ma , mb , mc; + struct tof_icc_toq_put aput; + + int flip = ((toq_cnt >> 11) & 1)^1; + int index = toq_cnt & 2047; + + mx = param.raddr.x; + my = param.raddr.y; + mz = param.raddr.z; + ma = param.raddr.a; + mb = param.raddr.b; + mc = param.raddr.c; + + memset(&aput, 0, sizeof(aput)); +// aput.head1.command = TOF_ICC_TOQ_PUT; + aput.head1.command = command; + aput.head1.mtuop.mtu = 240;/// MAX + aput.head1.pa = ma; + aput.head1.pb = mb; + aput.head1.pc = mc; + aput.head1.rx = mx; + aput.head1.ry = my; + aput.head1.rz = mz; + aput.head1.ra = ma; + aput.head1.rb = mb; + aput.head1.rc = mc; + aput.head1.ri = REMOTE().tni; + aput.head1.flip = flip ^ 1; /* current filp */ + aput.head2.s = 1; + if (mode & OPT_POLL) { /* receive polling */ + aput.head2.r = 0; + aput.head2.q = 0; + } else { + aput.head2.r = 0; + aput.head2.q = 1; + } + if (mode & OPT_CINJ) { /* cache injection */ + aput.head2.j = 1; + } else { + aput.head2.j = 0; + } + aput.head2.edata = toq_cnt; + aput.head2.len.normal.length = msglen; + aput.remote.stag = rstag; + aput.remote.offset = 0; /* always zero, checking alloc_stag */ + aput.remote.cqid = REMOTE().cq; + aput.local.stag = lstag; + aput.local.offset = 0; /* always zero, checking alloc_stag */ + aput.local.cqid = LOCAL().cq; + + memcpy(&toq[index], &aput, sizeof(aput)); + mb(); + toq[index].head1.flip = flip; /* write next flip */ + mb(); +} + +/* + * fetch start, + * wait update tcq, + * return rcode (0: Success) + */ +static int check_tcq (void) +{ + int rcode; + struct tof_icc_tcq_descriptor *tcq = param.tcq; + uint64_t *toq_reg = param.toq_reg; + uint64_t *toq_cnt = &(param.toq_cnt); + + int flip = ((*toq_cnt >> 11) & 1)^1; + int index = *toq_cnt & 2047; + + /* fetch start */ + do { + toq_reg[8] = 1; + } while (tcq[index].flip != flip); + mb(); + (*toq_cnt)++; + + rcode = tcq[index].rcode; + + /* check tcq */ + if (rcode) { + fprintf(stderr, "%s: rcode=%d\n", __FUNCTION__, rcode); + } + return rcode; +} + +/* + * wait update mrq + * return 0: Success, othrewise unintended id + */ +static int check_mrq (int continue_id, int break_id) +{ + struct tof_icc_mrq_descriptor *mrq = param.mrq; + uint64_t *mrq_cnt = &(param.mrq_cnt); + + int mrq_flip; + int id; + uint64_t index; + + while (1) { + mrq_flip = ((*mrq_cnt >> 17) & 1)^1; + index = *mrq_cnt & (4*1024*1024/32 - 1); + + if (mrq[index].head1.flip != mrq_flip) + continue; + mb(); + (*mrq_cnt)++; + id = mrq[index].head1.id; + + if (id == continue_id) + continue; + if (id == break_id) { + id = 0; + break; + } + + /* otherwise, unintended or error id */ + fprintf(stderr, "%s: id=%d wait=%d\n", __FUNCTION__, id, break_id); + break; + } + + return id; +} + +static inline void clear_msg (void *buf, int sec) +{ + int *ptr = (int *)(buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = MSG_INIT; + *(ptr - 1) = sec; + +// printf("%s: sec=%d\n", __FUNCTION__, *(ptr - 1)); +} + + +static int put_msg (int out_stag, int in_stag) +{ + int ret; + + tofu_putget(TOF_ICC_TOQ_PUT, CTRL_MSGLEN, (OPT_POLL | OPT_CINJ), + out_stag, in_stag); + + if ((ret = check_tcq()) != 0) { + return ret; + } + + return check_mrq(TOF_ICC_MRQ_PUT_NOTICE, TOF_ICC_MRQ_PUT_LAST_NOTICE); +} + +static int put_ctrl_msg (int msg) +{ + int *ptr = (int *)(param.ctrl_out_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = msg; + *(ptr - 1) += 1; + +// printf("%s: msg=%x sec=%d\n", __FUNCTION__, msg, *(ptr - 1)); + + return put_msg(LOCAL().ctrl_out_stag, REMOTE().ctrl_in_stag); +} + +static int get_data (void) +{ + int ret; + + /* + * Unset Q flag (set OPT_POLL) + * Get Halfway Notice is not required + */ + tofu_putget(TOF_ICC_TOQ_GET, param.length, OPT_POLL, + LOCAL().data_stag, REMOTE().data_stag); + + if ((ret = check_tcq()) != 0) { + return ret; + } + + return check_mrq(TOF_ICC_MRQ_GET_NOTICE, TOF_ICC_MRQ_GET_LAST_NOTICE); +} + +static int check_ctrl_msg (int msg, int clear) +{ + int ret = -1; + int *ptr = (int *)(param.ctrl_in_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + +#if 1 /* control message check */ + int val = *ptr; + int sec = *(ptr - 1); + + if (val == msg) { + if (clear) { + *ptr = MSG_INIT; +// printf("%s: req=%x, val=%x, sec=%d\n", __FUNCTION__, msg, val, sec); + } + ret = 0; + } else if (val != MSG_INIT) { + if (clear) { + /* clear = 0, touch buffer only */ + fprintf(stderr, "%s: Unexpected control message (req=%x, val=%x, sec=%d)\n", + __FUNCTION__, msg, val, sec); + } + } +#else + if (*ptr == msg) { + if (clear) { + *ptr = MSG_INIT; + } + ret = 0; + } +#endif + return ret; +} + +static int put_barrier_msg (void) +{ + int *ptr = (int *)(param.bar_out_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = MSG_BARRIER; + *(ptr - 1) = param.bar_cnt; + +// printf("%s: sec=%d\n", __FUNCTION__, *(ptr - 1)); + + return put_msg(LOCAL().bar_out_stag, REMOTE().bar_in_stag); +} + +static int check_barrier_msg (void) +{ + int *ptr = (int *)(param.bar_in_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + int val; + int sec; + + val = *ptr; + mb(); + sec = *(ptr - 1); + + if (val == MSG_INIT) + return -1; + + if (val == MSG_BARRIER && sec == param.bar_cnt) { + *ptr = MSG_INIT; +// printf("%s: sec=%d\n", __FUNCTION__, sec); + return 0; + } + + fprintf(stderr, "%s: Unexpected barrier message (val=%x, sec=%d, cnt=%d)\n", + __FUNCTION__, val, sec, param.bar_cnt); + return -1; +} + +static void tofu_barrier_init (void) +{ + param.bar_cnt = 0; + clear_msg(param.bar_in_buf, param.bar_cnt); + clear_msg(param.bar_out_buf,param.bar_cnt); +} + +static int tofu_barrier_wait (void) +{ + int ret = 0; + + if (IS_SEND()) { + (param.bar_cnt)++; + if (ret = put_barrier_msg()) { + fprintf(stderr, "%s: put MSG_BARRIER is failed(%d)\n", __FUNCTION__, ret); + return ret; + } + (param.bar_cnt)++; + while (check_barrier_msg()) { /* */ } + } else { + (param.bar_cnt)++; + while (check_barrier_msg()) { /* */ } + (param.bar_cnt)++; + if (ret = put_barrier_msg()) { + fprintf(stderr, "%s: put MSG_BARRIER is failed(%d)\n", __FUNCTION__, ret); + return ret; + } + } + + return ret; +} + + +/* send mode */ +static int __do_send (unsigned long *d) +{ + unsigned long t1, t2; + int ret; + + t1 = rdtsc_light(); + ret = put_ctrl_msg(MSG_CREAR_TO_GET); + if (ret == 0) { + while (check_ctrl_msg(MSG_DONE, 1)) { /* */ } + t2 = rdtsc_light(); + *d = t2 - t1; + } else { + fprintf(stderr, "%s: put MSG_CREAR_TO_GET is failed (%d)\n", + __FUNCTION__, ret); + } + + if (param.send_usleep) + usleep(param.send_usleep); + + return ret; +} + +static int do_send (void) +{ + unsigned long d2, tmp, min, max; + int ret, i; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + if (param.mode & SEND_FIFO) { + struct sched_param pri; + pri.sched_priority = sched_get_priority_min(SCHED_FIFO); + ret = sched_setscheduler(0, SCHED_FIFO, &pri); + if (ret) { + perror("sched_setscheduler"); + } + if (verbose) { + printf("%s: sched policy to sched_fifo\n", __FUNCTION__); + } + } + + /* Measure the reaction delay */ + min = -1UL; + max = 0UL; + d2 = 0UL; + for (i = 0; i < param.count; i++) { + /* Wait recv process */ + memset(param.data_buf, LOCAL().clear_pattern, param.length); + tofu_barrier_wait(); + usleep(1); + + if ((ret = __do_send(&tmp))) { + goto err_send; + } + + d2 += tmp; + min = (tmp < min ? tmp : min); + max = (tmp > max ? tmp : max); + + /* print result */ + printf("%lu\n", tmp); + + /* sync receiver/sender */ + tofu_barrier_wait(); + } + + /* print summary */ + d2 /= param.count; + printf("%s: reaction=%ld, min=%ld, max=%ld\n", + __FUNCTION__, d2, min, max); + +err_send: + return ret; +} + +/* recv mode with progress thread */ +static int __do_recv (void) +{ + int ret, i; + + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0; i < param.ctrl_retry; i++) { + if (!(ret = check_ctrl_msg(MSG_CREAR_TO_GET, 1))) { + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + + if ((ret = get_data())) { + fprintf(stderr, "%s: data_get is failed(%d)\n", __FUNCTION__, ret); + goto err__recv; + } + if ((ret = put_ctrl_msg(MSG_DONE))) { + fprintf(stderr, "%s: put MSG_DONE is failed(%d)\n", __FUNCTION__, ret); + goto err__recv; + } + + /* Set flags referenced by parent thread */ + recv_complete = 1; + +err__recv: + pthread_mutex_unlock(&mutex); + printf("%s: exit\n", __func__); + return ret; +} + +static int progress_func(void) +{ + int ret, i; + + for (i = 0; i < param.count; i++) { + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + if ((ret = __do_recv())) { + break; + } + } + + return ret; +} + +/* progress thread lock-check-unlock-yield overhead */ +static int progress_only_lock_unlock (void) +{ + int ret, i, p; + + for (i = 0; i < param.count; i++) { + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + + /* Check clear-to-get without buffer clear */ + while (1) { + pthread_mutex_lock(&mutex); + + for (p = 0; p < param.ctrl_retry; p++) { + check_ctrl_msg(MSG_CREAR_TO_GET, 0); + } + if (recv_complete) { /* check flag from parent */ + recv_complete = 0; + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + pthread_mutex_unlock(&mutex); + } + + return 0; +} + +static void *progress_thread(void *arg) +{ + int ret; + int (*func)(void) = (int (*)(void))(arg); + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + /* set priority */ + if (param.mode & THR_FIFO) { + struct sched_param pri; + pri.sched_priority = sched_get_priority_min(SCHED_FIFO); + ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &pri); + if (ret) { + perror("pthread_setschedparam"); + } + if (verbose) { + printf("%s: sched policy to sched_fifo\n", __FUNCTION__); + } + } else if (param.thr_prio != 0) { + ret = setpriority(PRIO_PROCESS, 0, param.thr_prio); + if (ret) { + fprintf(stderr, "%s: setpriority is failed (%d)\n", + __FUNCTION__, ret); + } + if (verbose || ret) { /* if setpriority is failed */ + errno = 0; + ret = getpriority(PRIO_PROCESS, 0); + printf("%s: getpriority = %d, errno = %d\n", + __FUNCTION__, ret, errno); + } + } + + if ((ret = func())) { + fprintf(stderr, "%s: progress function is failed (%d)\n", __FUNCTION__, ret); + } + + return NULL; +} + +static int initialize_thread_resources (pthread_t *thr, int (*func)(void)) +{ + pthread_attr_t attr; + cpu_set_t cpuset; + int ret; + + if ((ret = pthread_attr_init(&attr))) { + fprintf(stderr, "%s: pthread_attr_init is failed (%d)\n", + __FUNCTION__, ret); + goto err_res; + } + + if (onmck()) { + uti_attr_t uti_attr; + + /* on McKernel */ + if ((ret = uti_attr_init(&uti_attr))) { + fprintf(stderr,"%s: error: uti_attr_init failed with %d\n", __func__, ret); + goto err_res; + } + + if ((ret = UTI_ATTR_CPU_INTENSIVE(&uti_attr))) { + fprintf(stderr, "%s: error: UTI_ATTR_CPU_INTENSIVE failed\n", __func__); + goto err_res; + } + + printf("%s: calling uti_pthread_create\n", __func__); + if ((ret = uti_pthread_create(thr, &attr, progress_thread, (void *)func, &uti_attr))) { + fprintf(stderr, "%s: uti_pthread_create failed with %d\n", __FUNCTION__, ret); + } + } else { + /* on HostLinux, set thread affinity */ + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + CPU_SET(1, &cpuset); + ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); + if (ret) { + fprintf(stderr, "%s: pthread_attr_setaffinity_np is failed (%d)\n", + __FUNCTION__, ret); + goto err_res; + } + if ((ret = pthread_create(thr, &attr, progress_thread, (void *)func))) { + fprintf(stderr, "%s: uti_pthread_create failed with %d\n", __FUNCTION__, ret); + } + } + +err_res: + return ret; +} + +static int do_recv (void) +{ + int i, p; + int ret; + pthread_t thr; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + pthread_mutex_init(&mutex, NULL); + ret = pthread_barrier_init(&bar, NULL, 2); + if (ret) { + fprintf(stderr, "%s: pthread_barrier_init is failed (%d)\n", + __FUNCTION__, ret); + return ret; + } + + if ((param.mode & THR_MASK) == THR_NONE) { + /* nothing to do */ + } else if ((param.mode & THR_MASK) == THR_LCUY) { + /* progress thread lock-check-unlock-yield overhead */ + ret = initialize_thread_resources(&thr, progress_only_lock_unlock); + } else { + /* Normal mode */ + ret = initialize_thread_resources(&thr, progress_func); + } + if (ret) { + return ret; + } + + printf("%s: Measure the reaction delay, Ready\n", __FUNCTION__); + + /* Measure the reaction delay */ + for (i = 0; i < param.count; i++) { + + memset(param.data_buf, LOCAL().clear_pattern, param.length); + + if ((param.mode & THR_MASK) != THR_NONE) { + /* sync progress thread */ + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + } + + /* sync receiver/sender */ + pthread_mutex_lock(&mutex); + tofu_barrier_wait(); + pthread_mutex_unlock(&mutex); + + /* progress thread lock-check-unlock-yield overhead */ + if ((param.mode & THR_MASK) != THR_DEFAULT) { + if ((ret = __do_recv())) { + goto err_recv; + } + tofu_barrier_wait(); + continue; /* Measure loop continue */ + } + /* else Normal mode */ + + /* calc */ + if (param.delay) { + fwq(param.delay); + } + + /* wait progress thread */ + ret = -1; + while (1) { + pthread_mutex_lock(&mutex); + + for (p = 0; p < param.ctrl_retry; p++) { + if (recv_complete) { + ret = 0; + recv_complete = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + if (param.recv_usleep) { + usleep(param.recv_usleep); + } + } + pthread_mutex_unlock(&mutex); + + tofu_barrier_wait(); + } + +err_recv: + if ((param.mode & THR_MASK) != THR_NONE) { + pthread_join(thr, NULL); + if (verbose) { + printf("%s: progress thread is joined\n", __FUNCTION__); + } + } + return ret; +} + +/* dummy sender/receiver pair */ +static int dummy_send (void) +{ + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + while (!dummy_complete) { + usleep(10000); + } + + if (verbose) { + printf("%s: end, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + return 0; +} + +static int dummy_func (void) +{ + int i; + int ret= -1; + + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0; i < param.ctrl_retry; i++) { + if (!(ret = check_ctrl_msg(MSG_CREAR_TO_GET, 1))) { + break; + } + if (dummy_complete) { + ret = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + + recv_complete = 1; + pthread_mutex_unlock(&mutex); + return 0; +} + +static int dummy_func1 (void) +{ + pthread_mutex_lock(&mutex); + if (!recv_complete) { /* Wait main thread */ + pthread_cond_wait(&cond, &mutex); + } + pthread_mutex_unlock(&mutex); + return 0; +} + +static int dummy_recv (void) +{ + int i; + int ret; + pthread_t thr; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + + if (param.mode & DUMMY_MODE1) { + /* Progress thread waits for wake request from parent thread */ + if ((ret = initialize_thread_resources(&thr, dummy_func1))) { + return ret; + } + + while (!dummy_complete) { /* Wait SIGCHLD handler */ + usleep(10000); + sched_yield(); /* Todo */ + } + pthread_mutex_lock(&mutex); + recv_complete = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } else { + /* else, normal mode */ + if ((ret = initialize_thread_resources(&thr, dummy_func))) { + return ret; + } + + ret = -1; + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0;i < param.ctrl_retry; i++) { + if (recv_complete) { + ret = 0; + recv_complete = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + pthread_mutex_unlock(&mutex); + } + + pthread_join(thr, NULL); + if (verbose) { + printf("%s: progress thread is joined\n", __FUNCTION__); + } + return 0; +} + +static int args_to_param (int argc, char *argv[]) +{ + int ret; + + struct option longopts[] = { + /* only long opt */ + { "sendusleep", required_argument, NULL, 512}, + { "sendfifo", no_argument, NULL, 513}, + { "dummymode1", no_argument, NULL, 514}, + { "thrprio", required_argument, NULL, 515}, + { "thrfifo", no_argument, NULL, 516}, + { "protocol", no_argument, NULL, 517}, + { "ctrlretry", required_argument, NULL, 518}, + { "recvusleep", required_argument, NULL, 519}, + /* forward short opt */ + { "nortsig", no_argument, NULL, 's'}, + { "thread", required_argument, NULL, 't'}, + { "d1", required_argument, NULL, 'd'}, + { 0, 0, 0, 0 } + }; + + while ((ret = getopt_long(argc, argv, "a:d:t:srcf:n:l:v", longopts, NULL)) != -1) { + switch (ret) { + /* only long opt */ + case 512: /* usleep time for do_send */ + param.send_usleep = (int)strtol(optarg, NULL, 0); + break; + case 513: /* apply sched_fifo policy to do_send */ + param.mode |= SEND_FIFO; + break; + case 514: + param.mode |= DUMMY_MODE1; + break; + case 515: + param.thr_prio = (int)strtol(optarg, NULL, 0); + break; + case 516: + param.mode |= THR_FIFO; + break; + case 517: /* Measure protocol delay */ + param.forknum = 1; + param.mode |= THR_NONE; + break; + case 518: + param.ctrl_retry = (int)strtol(optarg, NULL, 0); + break; + case 519: + param.recv_usleep = (int)strtol(optarg, NULL, 0); + break; + /* forward short opt */ + case 'a': /* tofu coordinate */ + if (str2pos(optarg, &(param.raddr))) { + fprintf(stderr, "Failed to parse remote address"); + return -1; + } + break; + case 'd': /* protocol delay */ + param.delay = (int)strtol(optarg, NULL, 0); + break; + case 't': /* thread mode */ + if (strstr(optarg, "none") != NULL) { + param.mode |= THR_NONE; + } else if (strstr(optarg, "lcuy") != NULL) { + param.mode |= THR_LCUY; + } + break; + case 's': /* signal mode */ + param.mode &= ~OPT_RTSIG; + break; + case 'r': /* execute mode */ + param.mode |= MODE_RECV; + break; + case 'c': /* disable util_indicate_clone */ + param.mode &= ~OPT_SYSCALL; + break; + case 'f': /* fork, Process Generation Count */ + param.forknum = (int)strtol(optarg, NULL, 0); + if (param.forknum < 1) { + return -1; + } + break; + case 'n': /* Number of measurements of reaction delay */ + param.count = (int)strtol(optarg, NULL, 0); + break; + case 'l': /* data length */ + param.length = (int)strtol(optarg, NULL, 0); + break; + case 'v': /* verbose mode */ + verbose = 1; + break; + default: + return -1; + } + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + int ret; + int cq_fd; + int proc = 0; + pid_t cpid = 0; + cpu_set_t cpuset; + int i; + + param.forknum = 1; + param.mode = OPT_RTSIG | OPT_SYSCALL | MODE_SEND | THR_DEFAULT | DUMMY_MODE1; + param.delay = 0; + param.count = 10; + param.length = DATA_MSGLEN; + param.send_usleep = 100000; + param.recv_usleep = 0; + param.thr_prio = 10; + param.ctrl_retry = 10; + + if (args_to_param(argc, argv)) { + goto err_fork; + } + +#if 0 + { + struct rlimit l; + l.rlim_cur = RLIM_INFINITY; + l.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_CPU, &l)) + perror("RLIMIT_CPU"); + if(setrlimit(RLIMIT_NICE, &l)) + perror("RLIMIT_NICE"); + if(setrlimit(RLIMIT_RTPRIO, &l)) + perror("RLIMIT_RTPRIO"); + } +#endif + + /* fork, Multi process mode */ + for (i = 0; i < (param.forknum - 1); i++) { + cpid = fork(); + if (cpid == -1) { + perror("fork"); + goto err_fork; + } + if (cpid != 0) { + break; /* parent */ + } + /* cpid = 0, fork next child */ + } + /* set affinity */ + CPU_ZERO(&cpuset); + if (onmck()) { + CPU_SET(i, &cpuset); /* 0,1,2,3 ... */ + } else { + CPU_SET((i + 12), &cpuset); /* 12,13,14 ... */ + } + ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); + if (ret) { + perror("sched_setaffinity"); + goto err_open; + } + + /* override proc number */ + proc = i; + + /* setup signal */ + set_chldsignal(); + + if (verbose) { + printf("proc=%d, cpu=%d, pid=%d, cpid=%d\n", + proc, _getcpu(), getpid(), cpid); + } + + + /* setup test parameters */ + ret = setup_tp_param(proc); + if (ret) { + fprintf(stderr, "%s: setup_tp_param is failed\n", __FUNCTION__); + goto err_open; + } + + fwq_init(); +#if 0 + { /* fwq timer test */ + unsigned long t1, t2; + printf("nspw = %f, result of measuring 1 us \n", nspw); + for (i = 0; i < 10; i++) { + t1 = rdtsc_light(); + fwq(100); + t2 = rdtsc_light(); + printf("[%d] %ld ns\n", i, (t2 - t1) * 10); + } + } +#endif + + /* get cq_fd */ + { + char file[32]; + create_tofu_device_name(file, LOCAL().tni, LOCAL().cq); + + if (verbose) { + printf("open %s\n", file); + } + cq_fd = open(file, O_RDWR|O_CLOEXEC); + if (cq_fd < 0) { + perror("open"); + goto err_open; + } + } + + /* setup signal handler */ + if (param.mode & OPT_RTSIG) { + set_rtsignal(cq_fd); + } else { + set_termsignal(); + } + + /* memory mapping toq_reg */ + param.toq_reg = mmap(NULL, 4096, PROT_READ|PROT_WRITE, + MAP_SHARED, cq_fd, TOF_MMAP_CQ_REGISTER); + if (param.toq_reg == MAP_FAILED) { + perror("mmap"); + goto err_mmap; + } + + /* init cq */ + { + struct tof_init_cq req; + + req.version = TOF_UAPI_VERSION; + req.session_mode = 0; + req.toq_size = 0; /// 64KiB + req.mrq_size = 3; /// 4MiB + req.num_stag = 0; /// 8K + req.tcq_cinj = 1; + req.mrq_cinj = 1; + req.toq_mem = MMAP(64*1024); + req.tcq_mem = MMAP(16*1024); + req.mrq_mem = MMAP(4*1024*1024); + param.toq = req.toq_mem; + param.tcq = req.tcq_mem; + param.mrq = req.mrq_mem; + memset(param.toq, 0, 64*1024); + memset(param.tcq, 0, 16*1024); + memset(param.mrq, 0, 4*1024*1024); + ret = ioctl(cq_fd, TOF_IOCTL_INIT_CQ, &req); + if(ret != 0){ + perror("ioctl, TOF_IOCTL_INIT_CQ"); + goto err; + } + } + + /* alloc stag */ + param.ctrl_in_buf = MMAP(CTRL_MSGLEN); + param.ctrl_out_buf = MMAP(CTRL_MSGLEN); + param.bar_in_buf = MMAP(CTRL_MSGLEN); + param.bar_out_buf = MMAP(CTRL_MSGLEN); + param.data_buf = MMAP(param.length); + + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().ctrl_in_stag, param.ctrl_in_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().ctrl_out_stag, param.ctrl_out_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().bar_in_stag, param.bar_in_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().bar_out_stag, param.bar_out_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, param.length, LOCAL().data_stag, param.data_buf); + if (ret) { + goto err; + } + + param.toq_cnt = 0; + param.mrq_cnt = 0; + memset(param.data_buf, LOCAL().clear_pattern, param.length); + clear_msg(param.ctrl_in_buf, 0); + clear_msg(param.ctrl_out_buf, 0); + tofu_barrier_init(); + + if (cpid == 0) { + /* Single process mode or Last generated process */ + ret = (IS_SEND() ? do_send() : do_recv()); + } else { + ret = (IS_SEND() ? dummy_send() : dummy_recv()); + } + + if (ret) { + goto err; + } + + /* check signal */ + if (param.mrq_cnt > 4*1024*1024/32) { + if(((param.mode & OPT_RTSIG) && caused_signal_number > 32) || + (!(param.mode & OPT_RTSIG) && caused_signal_number == SIGTERM)){ + printf("sig=%d\n", caused_signal_number); + } + else{ + goto err; + } + } else if (verbose) { + printf("no signal\n"); + } + + /* TODO: resorce release */ + /* TODO: release MMAP() mapping */ +err: + munmap(param.toq_reg, 4096); +err_mmap: + close(cq_fd); +err_open: + /* Cleanup child process */ + if (cpid != 0) { + pid_t wpid; + + /* Wait for receipt of SIGCHLD */ + wpid = wait(&ret); + if (wpid == -1) { + perror("wait"); + } + if (verbose) { + printf("%s: wait cpid=%d wpid=%d status=%d\n", + __FUNCTION__, cpid, wpid, ret); + } + } +err_fork: + return 0; +} diff --git a/test/uti/tofu/wo_libuti/Makefile b/test/uti/tofu/wo_libuti/Makefile new file mode 100644 index 00000000..2e859f53 --- /dev/null +++ b/test/uti/tofu/wo_libuti/Makefile @@ -0,0 +1,20 @@ +# Makefile COPYRIGHT FUJITSU LIMITED 2021 + +CC = gcc +INC = -I../include +LDFLAGS = -lpthread +# CFLAGS = -g -Wall +CFLAGS = -g + +all: uti_perf ctrl + +ctrl: ctrl.c + $(CC) $(INC) $(LDFLAGS) $(CFLAGS) -o $@ $^ + +uti_perf: uti_perf.c + $(CC) $(INC) $(LDFLAGS) $(CFLAGS) -o $@ $^ + +.PHONY: clean +clean: + $(RM) -f uti_perf ctrl + diff --git a/test/uti/tofu/wo_libuti/ctrl.c b/test/uti/tofu/wo_libuti/ctrl.c new file mode 100644 index 00000000..7cce76bd --- /dev/null +++ b/test/uti/tofu/wo_libuti/ctrl.c @@ -0,0 +1,74 @@ +/* ctrl COPYRIGHT FUJITSU LIMITED 2021 */ +#include +#include +#include + +#include "tof_uapi.h" +#include "tof_test.h" + +int main(int argc, char *argv[]){ + int ctl_fd; + int res; + struct tof_addr laddr; + struct tof_reg_user req; + uint64_t cqmask[6] = {0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff}; + uint64_t bgmask[6] = {0xfffffffffff,0xfffffffffff,0xfffffffffff, + 0xfffffffffff,0xfffffffffff,0xfffffffffff}; + + + if(argc != 1 && argc != 10){ + printf("usage: %s \n", argv[0]); + printf(" ex. %s 1 1 12 0 0 8 1 1 4\n", argv[0]); + exit(1); + } + get_position(&laddr); + + /* REG_USER*/ + req.uid = 0; /// root? + req.gpid = 23456; + req.subnet.nx = laddr.x+1; + req.subnet.ny = laddr.y+1; + req.subnet.nz = laddr.z+1; + req.subnet.sx = laddr.x; + req.subnet.sy = laddr.y; + req.subnet.sz = laddr.z; + req.subnet.lx = 1; + req.subnet.ly = 1; + req.subnet.lz = 1; + req.cqmask = (uint64_t *)&cqmask; + req.bgmask = (uint64_t *)&bgmask; + + if(argc == 10){ + req.subnet.nx = strtol(argv[1], NULL, 10); + req.subnet.ny = strtol(argv[2], NULL, 10); + req.subnet.nz = strtol(argv[3], NULL, 10); + req.subnet.sx = strtol(argv[4], NULL, 10); + req.subnet.sy = strtol(argv[5], NULL, 10); + req.subnet.sz = strtol(argv[6], NULL, 10); + req.subnet.lx = strtol(argv[7], NULL, 10); + req.subnet.ly = strtol(argv[8], NULL, 10); + req.subnet.lz = strtol(argv[9], NULL, 10); + } + ctl_fd = open("/proc/tofu/dev/control", O_CLOEXEC); + if(ctl_fd < 0){ + TOF_EXIT(); + } + +/* + res = ioctl(ctl_fd, TOF_IOCTL_SET_SUBNET, &req.subnet); + if(res != 0){ + TOF_EXIT(); + } +*/ + res = ioctl(ctl_fd, TOF_IOCTL_REG_USER, &req); + if(res != 0){ + TOF_EXIT(); + } + printf("subnet= %d %d %d %d %d %d %d %d %d\n", + req.subnet.nx, req.subnet.ny, req.subnet.nz, + req.subnet.sx, req.subnet.sy, req.subnet.sz, + req.subnet.lx, req.subnet.ly, req.subnet.lz); + printf("success:L%d\n", __LINE__); + return 0; +} + diff --git a/test/uti/tofu/wo_libuti/uti_perf.c b/test/uti/tofu/wo_libuti/uti_perf.c new file mode 100644 index 00000000..b6ade35c --- /dev/null +++ b/test/uti/tofu/wo_libuti/uti_perf.c @@ -0,0 +1,1493 @@ +/* uti_perf COPYRIGHT FUJITSU LIMITED 2021 */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tof_uapi.h" +#include "tof_test.h" + +extern int __libc_allocate_rtsig (int __high); + +#define CTRL_MSGLEN (64) +#define DATA_MSGLEN (16 * 1024 * 1024 - 256) + +#define MSG_CREAR_TO_GET (0x58fca109U) +#define MSG_DONE (0x1105bf26U) +#define MSG_BARRIER (0x9c6108afU) +#define MSG_SEND_DELAY (0x61fb9044U) +#define MSG_INIT (0x065f8cbaU) + +#define RECV_PATTERN (0x00A0) +#define SEND_PATTERN (0x0050) + +/* param.mode bit */ +#define MODE_SEND (0x0000) +#define MODE_RECV (0x0001) +#define MODE_MASK (0x0001) + +#define THR_DEFAULT (0x0000) +#define THR_NONE (0x0002) /* do not create thread */ +#define THR_LCUY (0x0004) /* lock-check-unlock-yield */ +#define THR_MASK (0x0006) + +#define SEND_FIFO (0x00000010) +#define THR_FIFO (0x00000020) +#define DUMMY_MODE1 (0x00000040) + +#define OPT_RTSIG (0x01000000) +#define OPT_SYSCALL (0x02000000) +#define OPT_POLL (0x04000000) +#define OPT_CINJ (0x08000000) + +#define REMOTE() (param.remote) +#define LOCAL() (param.local) +#define IS_RECV() (((param.mode) & MODE_MASK) == MODE_RECV) +#define IS_SEND() (((param.mode) & MODE_MASK) == MODE_SEND) + +struct node_info { + int tni; + int cq; + int ctrl_in_stag; + int ctrl_out_stag; + int data_stag; + int bar_in_stag; + int bar_out_stag; + char clear_pattern; +}; + +struct tp_param { + int mode; + int delay; /* protocol delay, d1 */ + int count; /* number of measurements of delay */ + int length; /* data length */ + int forknum; /* number of processes */ + int send_usleep; /* usleep time for do_send */ + int recv_usleep; /* usleep time for do_recv */ + int thr_prio; /* progress thread priority */ + int ctrl_retry; /* ctrl retry count */ + struct tof_icc_toq_put *toq; + struct tof_icc_tcq_descriptor *tcq; + struct tof_icc_mrq_descriptor *mrq; + uint64_t *toq_reg; + uint64_t toq_cnt; + uint64_t mrq_cnt; + uint64_t bar_cnt; + struct tof_addr raddr; /* remote tofu address */ + void *ctrl_in_buf; + void *ctrl_out_buf; + void *data_buf; + void *bar_in_buf; + void *bar_out_buf; + + struct node_info local; /* constant data per node */ + struct node_info remote; +}; + +static int verbose = 0; +static struct tp_param param; + +static volatile int recv_complete = 0; +static volatile int dummy_complete = 0; + +static pthread_mutex_t mutex; +static pthread_cond_t cond; +static pthread_barrier_t bar; + +/* Fill constant parameters for the test */ +static int setup_tp_param (int proc) +{ + struct tof_addr laddr; + struct node_info *recv = IS_RECV() ? &LOCAL() : &REMOTE(); + struct node_info *send = IS_SEND() ? &LOCAL() : &REMOTE(); + + /* get local pos */ + /* TOF_EXIT(), if failed to get pos */ + get_position(&laddr); + + if ((laddr.x == param.raddr.x) && (laddr.a == param.raddr.a) && + (laddr.y == param.raddr.y) && (laddr.b == param.raddr.b) && + (laddr.z == param.raddr.z) && (laddr.c == param.raddr.c)) { + + /* same node, separate send/recv TNI */ + if (proc >= 11 || proc < 0) { + return -1; /* limit 11 process */ + } + recv->tni = 4; + recv->cq = proc; + send->tni = 5; + send->cq = proc; + + } else { + /* internode comm, use same TNI/CQ for send/recv */ + if (proc >= 48 || proc < 0) { + return -1; /* limit 48 process */ + } + send->tni = recv->tni = proc / 10 + 1; /* 1 - 5 */ + send->cq = recv->cq = proc % 10; /* 0 - 9 */ + } + + recv->ctrl_in_stag = recv->cq * 100 + recv->tni * 10 + 1; + recv->ctrl_out_stag = recv->cq * 100 + recv->tni * 10 + 2; + recv->data_stag = recv->cq * 100 + recv->tni * 10 + 3; + recv->bar_in_stag = recv->cq * 100 + recv->tni * 10 + 4; + recv->bar_out_stag = recv->cq * 100 + recv->tni * 10 + 5; + recv->clear_pattern = (char)(RECV_PATTERN + proc); + + send->ctrl_in_stag = send->cq * 100 + send->tni * 10 + 1; + send->ctrl_out_stag = send->cq * 100 + send->tni * 10 + 2; + send->data_stag = send->cq * 100 + send->tni * 10 + 3; + send->bar_in_stag = send->cq * 100 + send->tni * 10 + 4; + send->bar_out_stag = send->cq * 100 + send->tni * 10 + 5; + send->clear_pattern = (char)(SEND_PATTERN + proc); + + if (verbose) { + printf("mode : %s (proc=%d)\n", + (IS_RECV() ? "RECV" : "SEND"), proc); + printf("local : %d,%d,%d,%d,%d,%d tni=%d cq=%d\n", + laddr.x, laddr.y, laddr.z, laddr.a, laddr.b, laddr.c, + LOCAL().tni, LOCAL().cq); + printf("remote : %d,%d,%d,%d,%d,%d tni=%d cq=%d\n", + param.raddr.x, param.raddr.y, param.raddr.z, + param.raddr.a, param.raddr.b, param.raddr.c, + REMOTE().tni, REMOTE().cq); + } + return 0; +} + +/* create tofu device file name */ +static void create_tofu_device_name (char *file, int tni, int cq) +{ + strcpy(file, "/proc/tofu/dev/tni4cq0"); + file[18] = '0' + tni; + file[21] = '0' + cq; +} + +static int alloc_stag(int cq_fd, int msglen, int stag, void *buf) +{ + struct tof_alloc_stag alst; + int ret; + + alst.flags = 0; + alst.stag = stag; + alst.va = buf; + alst.len = msglen; + ret = ioctl(cq_fd, TOF_IOCTL_ALLOC_STAG, &alst); + if (ret != 0) { + perror("ioctl, TOF_IOCTL_ALLOC_STAG"); + return -1; + } + if (alst.offset != 0) { + fprintf(stderr, "%s: offset != 0\n", __FUNCTION__); + return -1; + } + + if (verbose) { + printf("va=%p len=%ld stag=%d offset=%ld\n", + alst.va, alst.len, alst.stag, alst.offset); + } + + return 0; +} + +int caused_signal_number = -1; + +void my_sig_action(int sig, siginfo_t *info, void *val){ + if(sig > 32){ + fprintf(stderr, "sig=%d si_int=0x%lx si_errno=%d si_code=%d\n", + sig, info->si_int, info->si_errno, info->si_code); + } + else { + fprintf(stderr, "sig=%d\n", sig); + } + fflush(stderr); + if(caused_signal_number == -1){ + caused_signal_number = sig; + } + else if(caused_signal_number != sig){ + fprintf(stderr, "2 different signal were sent: oldsig=%d newsig=%d\n", caused_signal_number, sig); + TOF_NG(); + TOF_EXIT(); + } +} + +void set_rtsignal(int fd){ + int sig; + int min, max; + int res; + struct sigaction sigact; + + min = SIGRTMIN; + max = SIGRTMAX; + sig = __libc_allocate_rtsig(1); + if(sig < min || sig > max){ + TOF_EXIT(); + } + res = ioctl(fd, TOF_SET_RT_SIGNAL, &sig); + if(res){ + TOF_EXIT(); + } + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = my_sig_action; + sigact.sa_flags = SA_SIGINFO; + sigemptyset(&sigact.sa_mask); + //sigaddset(&sigact.sa_mask, sig); + if(sigaction(sig, &sigact, NULL) != 0){ + TOF_EXIT(); + } + +// printf("setup signal\n"); +} + +void set_termsignal(void){ + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = my_sig_action; + //sigact.sa_flags = SA_SIGINFO; + sigemptyset(&sigact.sa_mask); + //sigaddset(&sigact.sa_mask, sig); + if(sigaction(SIGTERM, &sigact, NULL) != 0){ + TOF_EXIT(); + } +} + +static void chld_handler (int sig, siginfo_t *info, void *val) +{ + dummy_complete = 1; +} + +static void set_chldsignal (void) +{ + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = chld_handler; + sigemptyset(&sigact.sa_mask); + if(sigaction(SIGCHLD, &sigact, NULL) != 0){ + TOF_EXIT(); + } +} + +/* "0,1,2,3,4" -> {0,1,2,3,4} */ +static int str2int(const char *str, int *dst, int max) +{ + int i = 0; + char *s = (char *)str; + char *e; + + while (*s != '\0') { + dst[i] = (int)strtol(s, &e, 0); + + /* conversion failure */ + if (s == e) + break; + /* output buffer check */ + if (++i >= max) + break; + /* end of string */ + if (*e == '\0') + break; + /* get next pos */ + s = e + 1; + } + + return i; +} + +/* "0,1,2,3,4,5" -> struct tof_addr */ +static int str2pos(const char *str, struct tof_addr *addr) +{ + int dst[6]; + + if (str2int(str, dst, 6) == 6) { + addr->x = dst[0]; + addr->y = dst[1]; + addr->z = dst[2]; + addr->a = dst[3]; + addr->b = dst[4]; + addr->c = dst[5]; + return 0; + } else { + return 1; + } +} + +/* get 10ns (100MHz) timer counter */ +static inline unsigned long rdtsc_light(void) +{ + unsigned long x; + __asm__ __volatile__("isb \n\t" + "mrs %[output], cntvct_el0" + : [output]"=r"(x) + : + : "memory"); + return x; +} + +/* delay routine - begin */ +#define N_INIT 100000 +static double nspw = 0.0; /* 10 ns per work */ + +static inline void fixed_size_work (void) +{ + __asm__ __volatile__( + "mov x20, #0\n\t" + "1:\t" + "add x20, x20, #1\n\t" + "cmp x20, #99\n\t" + "b.le 1b\n\t" + : + : + : "x20", "cc", "memory"); +} + +static inline void bulk_fsw (unsigned long n) +{ + int j; + for(j = 0; j < n; j++) { + fixed_size_work(); + } +} + +static void fwq_init (void) +{ + unsigned long t1, t2; + t1 = rdtsc_light(); + bulk_fsw(N_INIT); + t2 = rdtsc_light(); + nspw = (double)(t2 - t1) / (double)N_INIT; +} + +static void fwq (long delay_10ns) +{ + if (delay_10ns >= 0) { + bulk_fsw(delay_10ns / nspw); + } +} +/* delay routine - end */ + +static int _getcpu (void) +{ + int cpu, ret; + + ret = syscall(SYS_getcpu, &cpu, NULL, NULL); + if (ret == -1) { + cpu = -1; + } + + return cpu; +} + +static int onmck (void) +{ + return (syscall(732) == -1 ? 0 : 1); +} + +/* + * tofu put/get + */ +static void tofu_putget ( + int command, int msglen, int mode, int lstag, int rstag) +{ + + struct tof_icc_toq_put *toq = param.toq; + uint64_t toq_cnt = param.toq_cnt; + + int mx , my , mz , ma , mb , mc; + struct tof_icc_toq_put aput; + + int flip = ((toq_cnt >> 11) & 1)^1; + int index = toq_cnt & 2047; + + mx = param.raddr.x; + my = param.raddr.y; + mz = param.raddr.z; + ma = param.raddr.a; + mb = param.raddr.b; + mc = param.raddr.c; + + memset(&aput, 0, sizeof(aput)); +// aput.head1.command = TOF_ICC_TOQ_PUT; + aput.head1.command = command; + aput.head1.mtuop.mtu = 240;/// MAX + aput.head1.pa = ma; + aput.head1.pb = mb; + aput.head1.pc = mc; + aput.head1.rx = mx; + aput.head1.ry = my; + aput.head1.rz = mz; + aput.head1.ra = ma; + aput.head1.rb = mb; + aput.head1.rc = mc; + aput.head1.ri = REMOTE().tni; + aput.head1.flip = flip ^ 1; /* current filp */ + aput.head2.s = 1; + if (mode & OPT_POLL) { /* receive polling */ + aput.head2.r = 0; + aput.head2.q = 0; + } else { + aput.head2.r = 0; + aput.head2.q = 1; + } + if (mode & OPT_CINJ) { /* cache injection */ + aput.head2.j = 1; + } else { + aput.head2.j = 0; + } + aput.head2.edata = toq_cnt; + aput.head2.len.normal.length = msglen; + aput.remote.stag = rstag; + aput.remote.offset = 0; /* always zero, checking alloc_stag */ + aput.remote.cqid = REMOTE().cq; + aput.local.stag = lstag; + aput.local.offset = 0; /* always zero, checking alloc_stag */ + aput.local.cqid = LOCAL().cq; + + memcpy(&toq[index], &aput, sizeof(aput)); + mb(); + toq[index].head1.flip = flip; /* write next flip */ + mb(); +} + +/* + * fetch start, + * wait update tcq, + * return rcode (0: Success) + */ +static int check_tcq (void) +{ + int rcode; + struct tof_icc_tcq_descriptor *tcq = param.tcq; + uint64_t *toq_reg = param.toq_reg; + uint64_t *toq_cnt = &(param.toq_cnt); + + int flip = ((*toq_cnt >> 11) & 1)^1; + int index = *toq_cnt & 2047; + + /* fetch start */ + do { + toq_reg[8] = 1; + } while (tcq[index].flip != flip); + mb(); + (*toq_cnt)++; + + rcode = tcq[index].rcode; + + /* check tcq */ + if (rcode) { + fprintf(stderr, "%s: rcode=%d\n", __FUNCTION__, rcode); + } + return rcode; +} + +/* + * wait update mrq + * return 0: Success, othrewise unintended id + */ +static int check_mrq (int continue_id, int break_id) +{ + struct tof_icc_mrq_descriptor *mrq = param.mrq; + uint64_t *mrq_cnt = &(param.mrq_cnt); + + int mrq_flip; + int id; + uint64_t index; + + while (1) { + mrq_flip = ((*mrq_cnt >> 17) & 1)^1; + index = *mrq_cnt & (4*1024*1024/32 - 1); + + if (mrq[index].head1.flip != mrq_flip) + continue; + mb(); + (*mrq_cnt)++; + id = mrq[index].head1.id; + + if (id == continue_id) + continue; + if (id == break_id) { + id = 0; + break; + } + + /* otherwise, unintended or error id */ + fprintf(stderr, "%s: id=%d wait=%d\n", __FUNCTION__, id, break_id); + break; + } + + return id; +} + +static inline void clear_msg (void *buf, int sec) +{ + int *ptr = (int *)(buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = MSG_INIT; + *(ptr - 1) = sec; + +// printf("%s: sec=%d\n", __FUNCTION__, *(ptr - 1)); +} + + +static int put_msg (int out_stag, int in_stag) +{ + int ret; + + tofu_putget(TOF_ICC_TOQ_PUT, CTRL_MSGLEN, (OPT_POLL | OPT_CINJ), + out_stag, in_stag); + + if ((ret = check_tcq()) != 0) { + return ret; + } + + return check_mrq(TOF_ICC_MRQ_PUT_NOTICE, TOF_ICC_MRQ_PUT_LAST_NOTICE); +} + +static int put_ctrl_msg (int msg) +{ + int *ptr = (int *)(param.ctrl_out_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = msg; + *(ptr - 1) += 1; + +// printf("%s: msg=%x sec=%d\n", __FUNCTION__, msg, *(ptr - 1)); + + return put_msg(LOCAL().ctrl_out_stag, REMOTE().ctrl_in_stag); +} + +static int get_data (void) +{ + int ret; + + /* + * Unset Q flag (set OPT_POLL) + * Get Halfway Notice is not required + */ + tofu_putget(TOF_ICC_TOQ_GET, param.length, OPT_POLL, + LOCAL().data_stag, REMOTE().data_stag); + + if ((ret = check_tcq()) != 0) { + return ret; + } + + return check_mrq(TOF_ICC_MRQ_GET_NOTICE, TOF_ICC_MRQ_GET_LAST_NOTICE); +} + +static int check_ctrl_msg (int msg, int clear) +{ + int ret = -1; + int *ptr = (int *)(param.ctrl_in_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + +#if 1 /* control message check */ + int val = *ptr; + int sec = *(ptr - 1); + + if (val == msg) { + if (clear) { + *ptr = MSG_INIT; +// printf("%s: req=%x, val=%x, sec=%d\n", __FUNCTION__, msg, val, sec); + } + ret = 0; + } else if (val != MSG_INIT) { + if (clear) { + /* clear = 0, touch buffer only */ + fprintf(stderr, "%s: Unexpected control message (req=%x, val=%x, sec=%d)\n", + __FUNCTION__, msg, val, sec); + } + } +#else + if (*ptr == msg) { + if (clear) { + *ptr = MSG_INIT; + } + ret = 0; + } +#endif + return ret; +} + +static int put_barrier_msg (void) +{ + int *ptr = (int *)(param.bar_out_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + *ptr = MSG_BARRIER; + *(ptr - 1) = param.bar_cnt; + +// printf("%s: sec=%d\n", __FUNCTION__, *(ptr - 1)); + + return put_msg(LOCAL().bar_out_stag, REMOTE().bar_in_stag); +} + +static int check_barrier_msg (void) +{ + int *ptr = (int *)(param.bar_in_buf) + (CTRL_MSGLEN / sizeof(int)) - 1; + int val; + int sec; + + val = *ptr; + mb(); + sec = *(ptr - 1); + + if (val == MSG_INIT) + return -1; + + if (val == MSG_BARRIER && sec == param.bar_cnt) { + *ptr = MSG_INIT; +// printf("%s: sec=%d\n", __FUNCTION__, sec); + return 0; + } + + fprintf(stderr, "%s: Unexpected barrier message (val=%x, sec=%d, cnt=%d)\n", + __FUNCTION__, val, sec, param.bar_cnt); + return -1; +} + +static void tofu_barrier_init (void) +{ + param.bar_cnt = 0; + clear_msg(param.bar_in_buf, param.bar_cnt); + clear_msg(param.bar_out_buf,param.bar_cnt); +} + +static int tofu_barrier_wait (void) +{ + int ret = 0; + + if (IS_SEND()) { + (param.bar_cnt)++; + if (ret = put_barrier_msg()) { + fprintf(stderr, "%s: put MSG_BARRIER is failed(%d)\n", __FUNCTION__, ret); + return ret; + } + (param.bar_cnt)++; + while (check_barrier_msg()) { /* */ } + } else { + (param.bar_cnt)++; + while (check_barrier_msg()) { /* */ } + (param.bar_cnt)++; + if (ret = put_barrier_msg()) { + fprintf(stderr, "%s: put MSG_BARRIER is failed(%d)\n", __FUNCTION__, ret); + return ret; + } + } + + return ret; +} + + +/* send mode */ +static int __do_send (unsigned long *d) +{ + unsigned long t1, t2; + int ret; + + t1 = rdtsc_light(); + ret = put_ctrl_msg(MSG_CREAR_TO_GET); + if (ret == 0) { + while (check_ctrl_msg(MSG_DONE, 1)) { /* */ } + t2 = rdtsc_light(); + *d = t2 - t1; + } else { + fprintf(stderr, "%s: put MSG_CREAR_TO_GET is failed (%d)\n", + __FUNCTION__, ret); + } + + if (param.send_usleep) + usleep(param.send_usleep); + + return ret; +} + +static int do_send (void) +{ + unsigned long d2, tmp, min, max; + int ret, i; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + if (param.mode & SEND_FIFO) { + struct sched_param pri; + pri.sched_priority = sched_get_priority_min(SCHED_FIFO); + ret = sched_setscheduler(0, SCHED_FIFO, &pri); + if (ret) { + perror("sched_setscheduler"); + } + if (verbose) { + printf("%s: sched policy to sched_fifo\n", __FUNCTION__); + } + } + + /* Measure the reaction delay */ + min = -1UL; + max = 0UL; + d2 = 0UL; + for (i = 0; i < param.count; i++) { + /* Wait recv process */ + memset(param.data_buf, LOCAL().clear_pattern, param.length); + tofu_barrier_wait(); + usleep(1); + + if ((ret = __do_send(&tmp))) { + goto err_send; + } + + d2 += tmp; + min = (tmp < min ? tmp : min); + max = (tmp > max ? tmp : max); + + /* print result */ + printf("%lu\n", tmp); + + /* sync receiver/sender */ + tofu_barrier_wait(); + } + + /* print summary */ + d2 /= param.count; + printf("%s: reaction=%ld, min=%ld, max=%ld\n", + __FUNCTION__, d2, min, max); + +err_send: + return ret; +} + +/* recv mode with progress thread */ +static int __do_recv (void) +{ + int ret, i; + + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0; i < param.ctrl_retry; i++) { + if (!(ret = check_ctrl_msg(MSG_CREAR_TO_GET, 1))) { + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + + if ((ret = get_data())) { + fprintf(stderr, "%s: data_get is failed(%d)\n", __FUNCTION__, ret); + goto err__recv; + } + if ((ret = put_ctrl_msg(MSG_DONE))) { + fprintf(stderr, "%s: put MSG_DONE is failed(%d)\n", __FUNCTION__, ret); + goto err__recv; + } + + /* Set flags referenced by parent thread */ + recv_complete = 1; + +err__recv: + pthread_mutex_unlock(&mutex); + return ret; +} + +static int progress_func (void) +{ + int ret, i; + + for (i = 0; i < param.count; i++) { + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + if ((ret = __do_recv())) { + break; + } + } + + return ret; +} + +/* progress thread lock-check-unlock-yield overhead */ +static int progress_only_lock_unlock (void) +{ + int ret, i, p; + + for (i = 0; i < param.count; i++) { + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + + /* Check clear-to-get without buffer clear */ + while (1) { + pthread_mutex_lock(&mutex); + + for (p = 0; p < param.ctrl_retry; p++) { + check_ctrl_msg(MSG_CREAR_TO_GET, 0); + } + if (recv_complete) { /* check flag from parent */ + recv_complete = 0; + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + pthread_mutex_unlock(&mutex); + } + + return 0; +} + +static void *progress_thread (void *arg) +{ + int ret; + int (*func)(void) = (int (*)(void))(arg); + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + /* set priority */ + if (param.mode & THR_FIFO) { + struct sched_param pri; + pri.sched_priority = sched_get_priority_min(SCHED_FIFO); + ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &pri); + if (ret) { + perror("pthread_setschedparam"); + } + if (verbose) { + printf("%s: sched policy to sched_fifo\n", __FUNCTION__); + } + } else if (param.thr_prio != 0) { + ret = setpriority(PRIO_PROCESS, 0, param.thr_prio); + if (ret) { + fprintf(stderr, "%s: setpriority is failed (%d)\n", + __FUNCTION__, ret); + } + if (verbose || ret) { /* if setpriority is failed */ + errno = 0; + ret = getpriority(PRIO_PROCESS, 0); + printf("%s: getpriority = %d, errno = %d\n", + __FUNCTION__, ret, errno); + } + } + + if ((ret = func())) { + fprintf(stderr, "%s: progress function is failed (%d)\n", __FUNCTION__, ret); + } + + return NULL; +} + +static int initialize_thread_resources (pthread_t *thr, int (*func)(void)) +{ + pthread_attr_t attr; + cpu_set_t cpuset; + int ret; + + if ((ret = pthread_attr_init(&attr))) { + fprintf(stderr, "%s: pthread_attr_init is failed (%d)\n", + __FUNCTION__, ret); + goto err_res; + } + + if (onmck()) { + /* on McKernel */ + if (param.mode & OPT_SYSCALL) { + ret = syscall(731, 1, NULL); + if (verbose || ret) { + printf("%s: on McKernel, util_indicate_clone = %d\n", + __FUNCTION__, ret); + } + } + } else { + /* on HostLinux, set thread affinity */ + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + CPU_SET(1, &cpuset); + ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); + if (ret) { + fprintf(stderr, "%s: pthread_attr_setaffinity_np is failed (%d)\n", + __FUNCTION__, ret); + goto err_res; + } + } + + if ((ret = pthread_create(thr, &attr, progress_thread, (void *)func))) { + fprintf(stderr, "%s: pthread_create is failed (%d)\n", __FUNCTION__, ret); + } + +err_res: + return ret; +} + +static int do_recv (void) +{ + int i, p; + int ret; + pthread_t thr; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + pthread_mutex_init(&mutex, NULL); + ret = pthread_barrier_init(&bar, NULL, 2); + if (ret) { + fprintf(stderr, "%s: pthread_barrier_init is failed (%d)\n", + __FUNCTION__, ret); + return ret; + } + + if ((param.mode & THR_MASK) == THR_NONE) { + /* nothing to do */ + } else if ((param.mode & THR_MASK) == THR_LCUY) { + /* progress thread lock-check-unlock-yield overhead */ + ret = initialize_thread_resources(&thr, progress_only_lock_unlock); + } else { + /* Normal mode */ + ret = initialize_thread_resources(&thr, progress_func); + } + if (ret) { + return ret; + } + + printf("%s: Measure the reaction delay, Ready\n", __FUNCTION__); + + /* Measure the reaction delay */ + for (i = 0; i < param.count; i++) { + + memset(param.data_buf, LOCAL().clear_pattern, param.length); + + if ((param.mode & THR_MASK) != THR_NONE) { + /* sync progress thread */ + ret = pthread_barrier_wait(&bar); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "%s: pthread_barrier_wait is failed (%d)\n", + __FUNCTION__, ret); + } + } + + /* sync receiver/sender */ + pthread_mutex_lock(&mutex); + tofu_barrier_wait(); + pthread_mutex_unlock(&mutex); + + /* progress thread lock-check-unlock-yield overhead */ + if ((param.mode & THR_MASK) != THR_DEFAULT) { + if ((ret = __do_recv())) { + goto err_recv; + } + tofu_barrier_wait(); + continue; /* Measure loop continue */ + } + /* else Normal mode */ + + /* calc */ + if (param.delay) { + fwq(param.delay); + } + + /* wait progress thread */ + ret = -1; + while (1) { + pthread_mutex_lock(&mutex); + + for (p = 0; p < param.ctrl_retry; p++) { + if (recv_complete) { + ret = 0; + recv_complete = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + if (param.recv_usleep) { + usleep(param.recv_usleep); + } + } + pthread_mutex_unlock(&mutex); + + tofu_barrier_wait(); + } + +err_recv: + if ((param.mode & THR_MASK) != THR_NONE) { + pthread_join(thr, NULL); + if (verbose) { + printf("%s: progress thread is joined\n", __FUNCTION__); + } + } + return ret; +} + +/* dummy sender/receiver pair */ +static int dummy_send (void) +{ + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + while (!dummy_complete) { + usleep(10000); + } + + if (verbose) { + printf("%s: end, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + return 0; +} + +static int dummy_func (void) +{ + int i; + int ret= -1; + + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0; i < param.ctrl_retry; i++) { + if (!(ret = check_ctrl_msg(MSG_CREAR_TO_GET, 1))) { + break; + } + if (dummy_complete) { + ret = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + + recv_complete = 1; + pthread_mutex_unlock(&mutex); + return 0; +} + +static int dummy_func1 (void) +{ + pthread_mutex_lock(&mutex); + if (!recv_complete) { /* Wait main thread */ + pthread_cond_wait(&cond, &mutex); + } + pthread_mutex_unlock(&mutex); + return 0; +} + +static int dummy_recv (void) +{ + int i; + int ret; + pthread_t thr; + + if (verbose) { + printf("%s: start, cpu=%d running on %s\n", + __FUNCTION__, _getcpu(), (onmck() ? "McKernel" : "Linux")); + } + + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + + if (param.mode & DUMMY_MODE1) { + /* Progress thread waits for wake request from parent thread */ + if ((ret = initialize_thread_resources(&thr, dummy_func1))) { + return ret; + } + + while (!dummy_complete) { /* Wait SIGCHLD handler */ + usleep(10000); + sched_yield(); /* Todo */ + } + pthread_mutex_lock(&mutex); + recv_complete = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } else { + /* else, normal mode */ + if ((ret = initialize_thread_resources(&thr, dummy_func))) { + return ret; + } + + ret = -1; + while (1) { + pthread_mutex_lock(&mutex); + for (i = 0;i < param.ctrl_retry; i++) { + if (recv_complete) { + ret = 0; + recv_complete = 0; + break; + } + } + if (!ret) { + break; + } + pthread_mutex_unlock(&mutex); + sched_yield(); + } + pthread_mutex_unlock(&mutex); + } + + pthread_join(thr, NULL); + if (verbose) { + printf("%s: progress thread is joined\n", __FUNCTION__); + } + return 0; +} + +static int args_to_param (int argc, char *argv[]) +{ + int ret; + + struct option longopts[] = { + /* only long opt */ + { "sendusleep", required_argument, NULL, 512}, + { "sendfifo", no_argument, NULL, 513}, + { "dummymode1", no_argument, NULL, 514}, + { "thrprio", required_argument, NULL, 515}, + { "thrfifo", no_argument, NULL, 516}, + { "protocol", no_argument, NULL, 517}, + { "ctrlretry", required_argument, NULL, 518}, + { "recvusleep", required_argument, NULL, 519}, + /* forward short opt */ + { "nortsig", no_argument, NULL, 's'}, + { "thread", required_argument, NULL, 't'}, + { "d1", required_argument, NULL, 'd'}, + { 0, 0, 0, 0 } + }; + + while ((ret = getopt_long(argc, argv, "a:d:t:srcf:n:l:v", longopts, NULL)) != -1) { + switch (ret) { + /* only long opt */ + case 512: /* usleep time for do_send */ + param.send_usleep = (int)strtol(optarg, NULL, 0); + break; + case 513: /* apply sched_fifo policy to do_send */ + param.mode |= SEND_FIFO; + break; + case 514: + param.mode |= DUMMY_MODE1; + break; + case 515: + param.thr_prio = (int)strtol(optarg, NULL, 0); + break; + case 516: + param.mode |= THR_FIFO; + break; + case 517: /* Measure protocol delay */ + param.forknum = 1; + param.mode |= THR_NONE; + break; + case 518: + param.ctrl_retry = (int)strtol(optarg, NULL, 0); + break; + case 519: + param.recv_usleep = (int)strtol(optarg, NULL, 0); + break; + /* forward short opt */ + case 'a': /* tofu coordinate */ + if (str2pos(optarg, &(param.raddr))) { + fprintf(stderr, "Failed to parse remote address"); + return -1; + } + break; + case 'd': /* protocol delay */ + param.delay = (int)strtol(optarg, NULL, 0); + break; + case 't': /* thread mode */ + if (strstr(optarg, "none") != NULL) { + param.mode |= THR_NONE; + } else if (strstr(optarg, "lcuy") != NULL) { + param.mode |= THR_LCUY; + } + break; + case 's': /* signal mode */ + param.mode &= ~OPT_RTSIG; + break; + case 'r': /* execute mode */ + param.mode |= MODE_RECV; + break; + case 'c': /* disable util_indicate_clone */ + param.mode &= ~OPT_SYSCALL; + break; + case 'f': /* fork, Process Generation Count */ + param.forknum = (int)strtol(optarg, NULL, 0); + if (param.forknum < 1) { + return -1; + } + break; + case 'n': /* Number of measurements of reaction delay */ + param.count = (int)strtol(optarg, NULL, 0); + break; + case 'l': /* data length */ + param.length = (int)strtol(optarg, NULL, 0); + break; + case 'v': /* verbose mode */ + verbose = 1; + break; + default: + return -1; + } + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + int ret; + int cq_fd; + int proc = 0; + pid_t cpid = 0; + cpu_set_t cpuset; + int i; + + param.forknum = 1; + param.mode = OPT_RTSIG | OPT_SYSCALL | MODE_SEND | THR_DEFAULT | DUMMY_MODE1; + param.delay = 0; + param.count = 10; + param.length = DATA_MSGLEN; + param.send_usleep = 100000; + param.recv_usleep = 0; + param.thr_prio = 10; + param.ctrl_retry = 10; + + if (args_to_param(argc, argv)) { + goto err_fork; + } + +#if 0 + { + struct rlimit l; + l.rlim_cur = RLIM_INFINITY; + l.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_CPU, &l)) + perror("RLIMIT_CPU"); + if(setrlimit(RLIMIT_NICE, &l)) + perror("RLIMIT_NICE"); + if(setrlimit(RLIMIT_RTPRIO, &l)) + perror("RLIMIT_RTPRIO"); + } +#endif + + /* fork, Multi process mode */ + for (i = 0; i < (param.forknum - 1); i++) { + cpid = fork(); + if (cpid == -1) { + perror("fork"); + goto err_fork; + } + if (cpid != 0) { + break; /* parent */ + } + /* cpid = 0, fork next child */ + } + /* set affinity */ + CPU_ZERO(&cpuset); + if (onmck()) { + CPU_SET(i, &cpuset); /* 0,1,2,3 ... */ + } else { + CPU_SET((i + 12), &cpuset); /* 12,13,14 ... */ + } + ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); + if (ret) { + perror("sched_setaffinity"); + goto err_open; + } + + /* override proc number */ + proc = i; + + /* setup signal */ + set_chldsignal(); + + if (verbose) { + printf("proc=%d, cpu=%d, pid=%d, cpid=%d\n", + proc, _getcpu(), getpid(), cpid); + } + + + /* setup test parameters */ + ret = setup_tp_param(proc); + if (ret) { + fprintf(stderr, "%s: setup_tp_param is failed\n", __FUNCTION__); + goto err_open; + } + + fwq_init(); +#if 0 + { /* fwq timer test */ + unsigned long t1, t2; + printf("nspw = %f, result of measuring 1 us \n", nspw); + for (i = 0; i < 10; i++) { + t1 = rdtsc_light(); + fwq(100); + t2 = rdtsc_light(); + printf("[%d] %ld ns\n", i, (t2 - t1) * 10); + } + } +#endif + + /* get cq_fd */ + { + char file[32]; + create_tofu_device_name(file, LOCAL().tni, LOCAL().cq); + + if (verbose) { + printf("open %s\n", file); + } + cq_fd = open(file, O_RDWR|O_CLOEXEC); + if (cq_fd < 0) { + perror("open"); + goto err_open; + } + } + + /* setup signal handler */ + if (param.mode & OPT_RTSIG) { + set_rtsignal(cq_fd); + } else { + set_termsignal(); + } + + /* memory mapping toq_reg */ + param.toq_reg = mmap(NULL, 4096, PROT_READ|PROT_WRITE, + MAP_SHARED, cq_fd, TOF_MMAP_CQ_REGISTER); + if (param.toq_reg == MAP_FAILED) { + perror("mmap"); + goto err_mmap; + } + + /* init cq */ + { + struct tof_init_cq req; + + req.version = TOF_UAPI_VERSION; + req.session_mode = 0; + req.toq_size = 0; /// 64KiB + req.mrq_size = 3; /// 4MiB + req.num_stag = 0; /// 8K + req.tcq_cinj = 1; + req.mrq_cinj = 1; + req.toq_mem = MMAP(64*1024); + req.tcq_mem = MMAP(16*1024); + req.mrq_mem = MMAP(4*1024*1024); + param.toq = req.toq_mem; + param.tcq = req.tcq_mem; + param.mrq = req.mrq_mem; + memset(param.toq, 0, 64*1024); + memset(param.tcq, 0, 16*1024); + memset(param.mrq, 0, 4*1024*1024); + ret = ioctl(cq_fd, TOF_IOCTL_INIT_CQ, &req); + if(ret != 0){ + perror("ioctl, TOF_IOCTL_INIT_CQ"); + goto err; + } + } + + /* alloc stag */ + param.ctrl_in_buf = MMAP(CTRL_MSGLEN); + param.ctrl_out_buf = MMAP(CTRL_MSGLEN); + param.bar_in_buf = MMAP(CTRL_MSGLEN); + param.bar_out_buf = MMAP(CTRL_MSGLEN); + param.data_buf = MMAP(param.length); + + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().ctrl_in_stag, param.ctrl_in_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().ctrl_out_stag, param.ctrl_out_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().bar_in_stag, param.bar_in_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, CTRL_MSGLEN, LOCAL().bar_out_stag, param.bar_out_buf); + if (ret) { + goto err; + } + ret = alloc_stag(cq_fd, param.length, LOCAL().data_stag, param.data_buf); + if (ret) { + goto err; + } + + param.toq_cnt = 0; + param.mrq_cnt = 0; + memset(param.data_buf, LOCAL().clear_pattern, param.length); + clear_msg(param.ctrl_in_buf, 0); + clear_msg(param.ctrl_out_buf, 0); + tofu_barrier_init(); + + if (cpid == 0) { + /* Single process mode or Last generated process */ + ret = (IS_SEND() ? do_send() : do_recv()); + } else { + ret = (IS_SEND() ? dummy_send() : dummy_recv()); + } + + if (ret) { + goto err; + } + + /* check signal */ + if (param.mrq_cnt > 4*1024*1024/32) { + if(((param.mode & OPT_RTSIG) && caused_signal_number > 32) || + (!(param.mode & OPT_RTSIG) && caused_signal_number == SIGTERM)){ + printf("sig=%d\n", caused_signal_number); + } + else{ + goto err; + } + } else if (verbose) { + printf("no signal\n"); + } + + /* TODO: resorce release */ + /* TODO: release MMAP() mapping */ +err: + munmap(param.toq_reg, 4096); +err_mmap: + close(cq_fd); +err_open: + /* Cleanup child process */ + if (cpid != 0) { + pid_t wpid; + + /* Wait for receipt of SIGCHLD */ + wpid = wait(&ret); + if (wpid == -1) { + perror("wait"); + } + if (verbose) { + printf("%s: wait cpid=%d wpid=%d status=%d\n", + __FUNCTION__, cpid, wpid, ret); + } + } +err_fork: + return 0; +}