vmware+ubuntu18+qemu调试kernel-arm64-vsock


环境:win11 + vmware17 + ubuntu18.04

一、环境搭建

1.qemu-8.0.2

https://download.qemu.org/
参考资料: https://wiki.qemu.org/Hosts/Linux

cd
mkdir kernel && cd kernel
wget -c https://download.qemu.org/qemu-8.0.2.tar.xz
tar xvJf qemu-8.0.2.tar.xz
cd qemu-8.0.2
mkdir compile_result && cd compile_result #编译后的目录
sudo apt-get install libpixman-1-dev
sudo apt install ninja-build
sudo apt-get install libglib2.0-dev
sudo apt install flex
../configure --prefix=$(pwd)  --enable-debug
make -j8 && sudo make install

2.buildroot

https://buildroot.org/download.html

 git clone git://git.busybox.net/buildroot
 sudo apt install libncurses-dev  -y
 make menuconfig

#配置好后编译
 make -j8
#编译好的结果会在output目录 

配置

在弹出的配置界面中,
设置
Target option ---> Target Architecture为
AArch64 (little endian);
设置
Toolchain ---> Toolchain type为
External toolchain,这时我们可以看到
Toolchain ---> Toolchain的值为
linaro AArch64 xxxx.xx;
设置
System configuration ---> Enable root login with password开启,并设置
System configuration ---> Root password为
xxxx(任意的你喜欢的密码);
设置
System configuration ---> Run a getty (login prompt) after boot ---> TTY port的值为
#按i编辑
ttyAMA0(这一条非常重要,不然虚拟机可能启动不了);
表示使用树莓派上的串口设备ttyAMA0作为终端设备
设置
Target packages ---> Show packages that are also provided by busybox开启;设置
Target packages ---> Debugging, profiling and benchmark ---> strace开启(应用程序和系统调用的信息追踪);设置
Filesystem images ---> cpio the root filesystem开启(生成cpio格式的根文件系统镜像)

3.编译工具链gcc-linaro-7.2.1

下载交叉编译工具链

https://releases.linaro.org/components/toolchain/binaries/

wget -c https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/aarch64-linux-gnu/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
sudo mkdir /home/toolchain
sudo tar xvJf gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz  -C /home/toolchain

4.linux kernel 5.16

https://www.kernel.org/
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/snapshot/linux-5.16.tar.gz

#下载内核源码:
wget -c https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.16.tar.xz
tar xvJf linux-5.16.tar.xz

config_kernel.sh

BUILD_DIR=$(pwd)/linux-5.16   

if [ ! -z $1 ]
then
                BUILD_DIR=$1
fi

export ARCH=arm64
export CROSS_COMPILE=/home/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
cd $BUILD_DIR
make menuconfig

配置内核

#运行config_kernel.sh后进行设置
设置
Boot options ---> (console=ttyAMA0) Default kernel command string
设置其值为console=ttyAMA0

设置
General setup  ---> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support                       
                        (/home/yyh/kernel/buildroot/output/images/rootfs.cpio) Initramfs source file(s)                       
设置其值为
$BUILD_ROOT_PATH/output/images/rootfs.cpio(注意,这里要自己展开变量BUILD_ROOT_PATH);
设置支持virtio-vsock
 [*] Networking support  --->  
                  Networking options  --->   
                                      <*> Virtual Socket protocol                                                                                            x x  
                                                <*>   Virtual Sockets monitoring interface (NEW)                                                                       x x  
                                                <*>   Virtual Sockets loopback transport (NEW)                                                                         x x  
                                                 <*>   virtio transport for Virtual Sockets   

build_kernel.sh

#! /bin/bash

BUILD_DIR=$(pwd)/linux-5.16

if [ ! -z $1 ]
then
    BUILD_DIR=$1
fi

export ARCH=arm64
export CROSS_COMPILE=/home/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
cd $BUILD_DIR
make -j8

5.启动虚拟机

(1)创建磁盘镜像文件

$(pwd)/qemu-8.0.2/compile_result/qemu-img create -f qcow2 test-qcow2.img  10G

(2)拷贝内核镜像和根文件系统到指定目录

mkdir img_space && cd img_space
mv ../test-qcow2.img .
cp /home/yyh/kernel/buildroot/output/images/rootfs.cpio .
cp /home/yyh/kernel/linux-5.16/arch/arm64/boot/Image .

(3)配置和管理虚拟机网络接口

参考:https://blog.csdn.net/chengbeng1745/article/details/81271024
https://www.jianshu.com/p/110b60c14a8b
/etc/qemu-ifup脚本在启动虚拟机的网络接口时运行,用于配置虚拟机的IP地址、子网掩码、网关等

sudo vim /etc/qemu-ifup
#添加如下内容

#!/bin/sh
switch=br0
interface=ens33
if [ -n "$1" ]; then
    switch_exit=`sudo ifconfig -a | grep $switch`
    interface_switch=`sudo brctl show | grep $interface`
    if [ "$switch_exit" = "" ] ; then
        sudo brctl addbr $switch
    fi
   if [ "$interface_switch" = "" ] ; then
       sudo ifconfig $interface 0.0.0.0 promisc up
       sudo brctl addif $switch $interface
    fi
    sudo ifconfig $1 0.0.0.0 promisc up
    sudo brctl addif $switch $1
    sudo dhclient $switch
else
   echo "Error: no interface specified"
   exit
fi

/etc/qemu-ifdown脚本在关闭虚拟机的网络接口时运行,用于清除虚拟机的网络配置

sudo vim /etc/qemu-ifdown
#添加如下内容
#! /bin/sh

switch=br0
if [ -n "$1" ]; then

#    sudo tunctl -d $1
    sudo brctl delif $switch $1
    sudo ifconfig $1 down
else
    echo "error: no interface specified"
    exit 1
fi

在Linux中创建一个桥接接口br0,并将物理接口eth0添加到该桥接接口上。这样虚拟机可以通过eth0与宿主机进行网络通信。配置好后重启系统sudo reboot

sudo chmod +x /etc/qemu-*
sudo apt-get install uml-utilities bridge-utils 
sudo vim /etc/network/interfaces
#添加如下内容
auto eth0
iface eth0 inet manual

auto br0
iface br0 inet dhcp
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0

#创建一个名为br0的桥接接口,并使用DHCP协议自动分配IP地址
#bridge_ports eth0表示将物理接口eth0添加到桥接接口br0上
#bridge_stp off表示关闭STP(Spanning Tree Protocol)
#bridge_fd 0表示禁用桥接接口的转发延迟

(4)虚拟机启动脚本start_qemu_arm64_vsock.sh

#!/bin/sh

QEMU_PATH=$(pwd)/qemu-8.0.2/compile_result/aarch64-softmmu/qemu-system-aarch64
KERNEL_IMG_PATH=$(pwd)/img_space/Image
DISK_IMG_PATH=$(pwd)/img_space/test-qcow2.img
ROOTFS_IMG_PATH=$(pwd)/img_space/rootfs.cpio

MEM_SIZE="4G"
CPU_CORES="4"
NETDEV_TYPE="tap"
NETDEV_ID="net0"
NETDEV_IFNAME="tap0"
NETDEV_SCRIPT="/etc/qemu-ifup"
NETDEV_DOWNSCRIPT="/etc/qemu-ifdown"

sudo \
    $QEMU_PATH \
    -machine virt,accel=tcg \
    -m $MEM_SIZE \
    -smp $CPU_CORES \
    -kernel $KERNEL_IMG_PATH \
    -initrd $ROOTFS_IMG_PATH \
    -append "console=ttyAMA0" \
    -drive file=$DISK_IMG_PATH,format=qcow2,if=virtio,id=hdw \
    -netdev $NETDEV_TYPE,id=$NETDEV_ID,ifname=$NETDEV_IFNAME,script=$NETDEV_SCRIPT,downscript=$NETDEV_DOWNSCRIPT \
    -device virtio-net-pci,netdev=$NETDEV_ID \
    -device vhost-vsock-device,guest-cid=3 \
    -cpu cortex-a57 \
    -serial stdio \
    -display none

qemu相关参数


-machine指定虚拟机的架构和加速器,这里使用了virt和tcg

-m指定虚拟机的内存大小

-smp指定虚拟机的CPU核心数

-kernel指定内核镜像文件的路径

-initrd指定根文件系统镜像文件的路径

-append指定内核的启动参数

-drive指定磁盘镜像文件、格式、接口和ID

-netdev指定网络设备类型、ID、名称、启动脚本和关闭脚本

-device指定设备类型和ID

-cpu指定CPU类型

-serial指定串行控制台

-display指定显示设备类型

二、测试vsock

参考:http://www.manongjc.com/detail/20-yjvqsrjykkxqwfq.html

1.运行start_qemu_arm64_vsock.sh启动虚拟机

在这里插入图片描述

2.编译代码

https://chromium.googlesource.com/chromiumos/platform2/+/9e91613d2da1b3d6cfb1c77681444e688ce99cf4/vm_tools/docs/vsock.md
在这里插入图片描述

v_cli目录下的makefile

CC =/home/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc 
#CC = gcc
CFLAGS = #-Wall -Werror
INCLUDES = 
LDFLAGS = 
LIBS = 
SRCS = vsock_client.c
OBJS = $(SRCS:.c=.o)
TARGET = cli

all: $(TARGET)
$(TARGET): $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
%.o: %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
clean:
    rm -f $(OBJS) $(TARGET)

v_server目录下的makefile

#CC =/home/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc 
CC = gcc
CFLAGS = #-Wall -Werror
INCLUDES = 
LDFLAGS = 
LIBS = 
SRCS = vsock_server.c
OBJS = $(SRCS:.c=.o)
TARGET = ser

all: $(TARGET)
$(TARGET): $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
%.o: %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
clean:
    rm -f $(OBJS) $(TARGET)

3.通过tftp将cli文件传输至arm64虚拟机

在这里插入图片描述

windows启动tftp服务器,将编译好的cli放在设置好的共享目录

#arm64虚拟机通过tftp获取cli文件
tftp -gr cli 192.168.11.29
chmod +x cli
3.运行测试
#ubnutu18.04运行ser
./ser
#arm64虚拟机运行cli
./cli

在这里插入图片描述

4.多线程并发测试

ser

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <linux/vm_sockets.h>

void* pthread_fun(void* arg)
{
    int c = *(int*)arg;
    free(arg);

    while (1)
    {
        char buff[128] = {0};
        int n = recv(c, buff, 127, 0);
        if (n <= 0)
        {
            break;
        }
        printf("recv(%d)=%s\n", c, buff);
        send(c, "OK", 2, 0);
    }

    close(c);
    pthread_exit(NULL);
}

int main()
{
    int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
    assert(sockfd != -1);

    struct sockaddr_vm saddr, caddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.svm_family = AF_VSOCK;
    saddr.svm_cid =  VMADDR_CID_HOST;
    saddr.svm_port = 9999;

    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
    assert(res != -1);

    listen(sockfd, 5);

    while (1)
    {
        struct sockaddr_vm caddr;
        memset(&caddr, 0, sizeof(caddr));
        int len = sizeof(caddr);
        int* c = (int*)malloc(sizeof(int));
        *c = accept(sockfd, (struct sockaddr*)&caddr, &len);
        if (*c < 0)
        {
            free(c); 
            continue;
        }
        printf("accept = %d\n", *c);
        pthread_t id;
        pthread_create(&id, NULL, pthread_fun, (void*)c);
    }

    close(sockfd);
    exit(0);
}


cli

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/vm_sockets.h>
#include <string.h>

int main()
{
  		char buf[64];
        int msg_len;
        int s = socket(AF_VSOCK, SOCK_STREAM, 0);

        struct sockaddr_vm addr;
        memset(&addr, 0, sizeof(struct sockaddr_vm));
        addr.svm_family = AF_VSOCK;
        addr.svm_port = 9999;
        addr.svm_cid = VMADDR_CID_HOST;

        connect(s, &addr, sizeof(struct sockaddr_vm));
        send(s, "Hello, world!", 13, 0);
      

        printf("line %d recv from android start\n",__LINE__);
        msg_len = recv(s, &buf, 64, 0);
        printf("Received %d bytes: %s\n", msg_len, buf);
        
        while(1) {
                int ret = send(s, "Hello, world!", 13, 0);
                if(ret < 0) {
                        perror("send break");
                        break;
                }
                sleep(1);
        }
        close(s);
        printf("close !\n");

        return 0;
}

5.epoll ser

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <linux/vm_sockets.h>

#define MAX_EVENTS  20
#define MAX_CLIENTS 20

int main() {
    int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
    assert(sockfd != -1);

    struct sockaddr_vm saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.svm_family = AF_VSOCK;
    saddr.svm_cid = VMADDR_CID_HOST;
    saddr.svm_port = 9999;

    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
    assert(res != -1);

    listen(sockfd, 5);

    int epollfd = epoll_create1(0);
    assert(epollfd != -1);

    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = sockfd;
    res = epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event);
    assert(res != -1);

    struct epoll_event events[MAX_EVENTS];

    int num_clients = 0;
    int i;

    while (1) {
        int num_ready = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        assert(num_ready != -1);

        for (i = 0; i < num_ready; i++) {
            if (events[i].data.fd == sockfd) {
                struct sockaddr_vm caddr;
                memset(&caddr, 0, sizeof(caddr));
                socklen_t len = sizeof(caddr);
                int c = accept(sockfd, (struct sockaddr*)&caddr, &len);
                if (c < 0) {
                    perror("accept error");
                    continue;
                }

                printf("accept = %d\n", c);
                if (num_clients >= MAX_CLIENTS) {
                    printf("Maximum number of clients reached. Rejecting new connection.\n");
                    close(c);
                    continue;
                }

                event.events = EPOLLIN | EPOLLRDHUP;
                event.data.fd = c;
                res = epoll_ctl(epollfd, EPOLL_CTL_ADD, c, &event);
                assert(res != -1);

                num_clients++;

            } else {
                int clientfd = events[i].data.fd;
                if (events[i].events & EPOLLIN) {
                    char recv_buff[128] = {0};
                    int n = recv(clientfd, recv_buff, sizeof(recv_buff) - 1, 0);
                    if (n <= 0) {
                        res = epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
                        //assert(res != -1);
                        if(res == -1) {
                             perror("epoll");
                        }

                        close(clientfd);
                        printf("close %d!\n", clientfd);
                        num_clients--;
                    } else {
                        recv_buff[n] = '\0';
                        printf("recv(%d)=%s\n", clientfd, recv_buff);
                        char send_buff[128];
                        sprintf(send_buff, "OK! your number %d", clientfd);
                        send(clientfd, send_buff, strlen(send_buff), 0);
                    }
                }

                if (events[i].events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
                    res = epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
                    //assert(res != -1);
                    if(res == -1)
                    {
                        perror("epoll");
                    }

                    close(clientfd);
                    printf("close %d!\n", clientfd);
                    num_clients--;
                }
            }
        }
    }

    close(epollfd);
    close(sockfd);
    exit(0);
}

6.vsock-perf

// SPDX-License-Identifier: GPL-2.0-only
/*
 * vsock_perf - benchmark utility for vsock.
 *
 * Copyright (C) 2022 SberDevices.
 *
 * Author: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
 */
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <poll.h>
#include <sys/socket.h>
#include <linux/vm_sockets.h>
#include <sys/time.h>
#include <sys/syscall.h>

#define DEFAULT_BUF_SIZE_BYTES	(128 * 1024)
#define DEFAULT_TO_SEND_BYTES	(64 * 1024)
#define DEFAULT_VSOCK_BUF_BYTES (256 * 1024)
#define DEFAULT_RCVLOWAT_BYTES	1
#define DEFAULT_PORT		1234

#define BYTES_PER_GB		(1024 * 1024 * 1024ULL)
#define NSEC_PER_SEC		(1000000000ULL)
#define NSEC_PER_MSEC		(1000000ULL)

static unsigned int port = DEFAULT_PORT;
static unsigned long buf_size_bytes = DEFAULT_BUF_SIZE_BYTES;
static unsigned long vsock_buf_bytes = DEFAULT_VSOCK_BUF_BYTES;

static void error(const char *s)
{
	perror(s);
	exit(EXIT_FAILURE);
}

static time_t current_nsec(void)
{
	struct timespec ts;

	if (clock_gettime(CLOCK_REALTIME, &ts))
		error("clock_gettime");

	return (ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec;
}

/* From lib/cmdline.c. */
static unsigned long memparse(const char *ptr)
{
	char *endptr;

	unsigned long long ret = strtoull(ptr, &endptr, 0);

	switch (*endptr) {
	case 'E':
	case 'e':
		ret <<= 10;
	case 'P':
	case 'p':
		ret <<= 10;
	case 'T':
	case 't':
		ret <<= 10;
	case 'G':
	case 'g':
		ret <<= 10;
	case 'M':
	case 'm':
		ret <<= 10;
	case 'K':
	case 'k':
		ret <<= 10;
		endptr++;
	default:
		break;
	}

	return ret;
}

static void vsock_increase_buf_size(int fd)
{
	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
		       &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
		error("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");

	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
		       &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
		error("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
}

static int vsock_connect(unsigned int cid, unsigned int port)
{
	union {
		struct sockaddr sa;
		struct sockaddr_vm svm;
	} addr = {
		.svm = {
			.svm_family = AF_VSOCK,
			.svm_port = port,
			.svm_cid = cid,
		},
	};
	int fd;

	fd = socket(AF_VSOCK, SOCK_STREAM, 0);

	if (fd < 0) {
		perror("socket");
		return -1;
	}

	if (connect(fd, &addr.sa, sizeof(addr.svm)) < 0) {
		perror("connect");
		close(fd);
		return -1;
	}

	return fd;
}

static float get_gbps(unsigned long bits, time_t ns_delta)
{
	return ((float)bits / 1000000000ULL) /
	       ((float)ns_delta / NSEC_PER_SEC);
}

static void run_receiver(unsigned long rcvlowat_bytes)
{
	unsigned int recv_cnt,send_cnt;
	time_t begin_ns;
	time_t total_ns;
	time_t in_recv_ns;
	time_t in_send_ns;
	size_t total_recv;
	size_t total_send;
	int client_fd;
	char *data;
	int fd;
	union {
		struct sockaddr sa;
		struct sockaddr_vm svm;
	} addr = {
		.svm = {
			.svm_family = AF_VSOCK,
			.svm_port = port,
			.svm_cid = VMADDR_CID_HOST,
		},
	};
	union {
		struct sockaddr sa;
		struct sockaddr_vm svm;
	} clientaddr;

	socklen_t clientaddr_len = sizeof(clientaddr.svm);

	printf("Run as receiver %d\n",addr.svm.svm_cid);
	printf("Listen port %u\n", port);
	printf("TX buffer %lu bytes\n", buf_size_bytes);
	printf("vsock buffer %lu bytes\n", vsock_buf_bytes);
	printf("SO_RCVLOWAT %lu bytes\n", rcvlowat_bytes);

	fd = socket(AF_VSOCK, SOCK_STREAM, 0);

	if (fd < 0)
		error("socket");
       
	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0)
		error("bind");

	if (listen(fd, 1) < 0)
		error("listen");

	client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);

	if (client_fd < 0)
		error("accept");

	vsock_increase_buf_size(client_fd);

    if (setsockopt(client_fd, SOL_SOCKET, SO_RCVLOWAT,
		       &rcvlowat_bytes,
		       sizeof(rcvlowat_bytes)))
		error("setsockopt(SO_RCVLOWAT)");

    data = malloc(buf_size_bytes);

	if (!data) {
		fprintf(stderr, "'malloc()' failed\n");
		exit(EXIT_FAILURE);
	}

	recv_cnt = 0;
	send_cnt = 0;
	in_recv_ns = 0;
	in_send_ns = 0;
	total_recv = 0;
	total_send = 0;
	begin_ns = current_nsec();

	while (1) {
		struct pollfd fds = { 0 };

		fds.fd = client_fd;
		fds.events = POLLIN | POLLERR |
			     POLLHUP | POLLRDHUP;

		if (poll(&fds, 1, -1) < 0)
			error("poll");

		if (fds.revents & POLLERR) {
			fprintf(stderr, "'poll()' error\n");
			exit(EXIT_FAILURE);
		}

		if (fds.revents & POLLIN) {

			ssize_t bytes_recv,bytes_send = 0,tmp_bytes_send = 0;
			time_t t;

			t = current_nsec();
			bytes_recv = recv(client_fd, data, buf_size_bytes,0);
			in_recv_ns += (current_nsec() - t);
			recv_cnt++;

			if (!bytes_recv)
				break;

			if (bytes_recv < 0) {
				perror("recv");
				exit(EXIT_FAILURE);
			}

			total_recv += bytes_recv;
			while(tmp_bytes_send < bytes_recv) {
				t = current_nsec();
				bytes_send = send(client_fd, data, bytes_recv,0);
				in_send_ns += (current_nsec() - t);
				send_cnt++;

				if (!bytes_send)
					break;

				if (bytes_send < 0) {
					perror("send");
					exit(EXIT_FAILURE);
				}
				tmp_bytes_send += bytes_send;
				total_send += bytes_send;
			}
		}
		if (fds.revents & (POLLHUP | POLLRDHUP))
		break;
	}

	total_ns = current_nsec() - begin_ns;
	printf("total bytes received: %zu\n", total_recv);
	printf("tx performance: %f Gbits/s\n",
	       get_gbps(total_recv * 8, in_recv_ns));
	printf("total time in 'recv()': %f sec\n", (float)in_recv_ns / NSEC_PER_SEC);
	printf("average time in 'recv()': %f ns\n", (float)in_recv_ns / recv_cnt);
	printf("POLLIN wakeups: %i\n", recv_cnt);

	
	printf("total bytes send: %zu\n", total_send);
	printf("rx performance: %f Gbits/s\n",
	       get_gbps(total_send * 8,in_send_ns));
	printf("total time in 'send()': %f sec\n", (float)in_send_ns / NSEC_PER_SEC);
	printf("average time in 'send()': %f ns\n", (float)in_send_ns / send_cnt);

	printf("total time in 'send recv': %f sec\n",
	       (float)total_ns / NSEC_PER_SEC);
	printf("recv_cnt %d send_cnt %d \n",recv_cnt,send_cnt);

	printf("time-delay %lf ms\n",((double)total_ns / NSEC_PER_MSEC)/(recv_cnt + send_cnt));
	printf("throughput %lf Mbps\n",((double)(total_recv + total_send)*8)/(size_t)((float)total_ns / NSEC_PER_SEC)/(1000000));

	free(data);
	close(client_fd);
	close(fd);
}

static void run_sender(int peer_cid, unsigned long to_send_bytes)
{
	time_t begin_ns;
	time_t total_ns;
	time_t in_recv_ns;
	time_t in_send_ns;
	size_t total_send;
	size_t total_recv;
	size_t send_cnt;
	size_t recv_cnt;
	void *data;
	int fd;

	printf("Run as sender\n");
	printf("Connect to %i:%u\n", peer_cid, port);
	printf("Send %lu bytes\n", to_send_bytes);
	printf("TX buffer %lu bytes\n", buf_size_bytes);

	fd = vsock_connect(peer_cid, port);

	if (fd < 0)
		exit(EXIT_FAILURE);

	data = malloc(buf_size_bytes);

	if (!data) {
		fprintf(stderr, "'malloc()' failed\n");
		exit(EXIT_FAILURE);
	}

	memset(data, 0, buf_size_bytes);
	total_send = 0;
	total_recv = 0;
	in_send_ns = 0;
	in_recv_ns = 0;
	send_cnt = 0;
	recv_cnt = 0;
	begin_ns = current_nsec();
	while (total_send < to_send_bytes) {
		ssize_t sent,tmp_recvd = 0,recvd = 0;
		time_t t;

		t = current_nsec();
		sent = send(fd, data, buf_size_bytes, 0);
		in_send_ns += (current_nsec() - t);
		if (sent <= 0) {
			error("send");
			exit(EXIT_FAILURE);
		}

		send_cnt++;
		total_send += sent;
		while (tmp_recvd < sent)
		{
			t = current_nsec();
			recvd = recv(fd, data, sent, 0);
			in_recv_ns += (current_nsec() - t);
			if (recvd <= 0) {
				error("recv");
				exit(EXIT_FAILURE);
			}
			recv_cnt++;
			tmp_recvd += recvd;
			total_recv += recvd;
		}
	}

	total_ns = current_nsec() - begin_ns;

	printf("total bytes sent: %zu\n", total_send);
	printf("tx performance: %f Gbits/s\n",
	       get_gbps(total_send * 8, in_send_ns));
	printf("total time in 'send()': %f sec\n", (float)in_send_ns / NSEC_PER_SEC);
	printf("average time in 'send()': %f ns\n", (float)in_send_ns / send_cnt);

	printf("total bytes recv: %zu\n", total_recv);
	printf("rx performance: %f Gbits/s\n",
			get_gbps(total_recv * 8, in_recv_ns));
	printf("total time in 'recv()': %f sec\n", (float)in_recv_ns / NSEC_PER_SEC);
	printf("average time in 'recv()': %f ns\n", (float)in_recv_ns / recv_cnt);

	
	printf("total time in 'send recv': %f sec\n",
	       (float)total_ns / NSEC_PER_SEC);
	

	close(fd);
	free(data);
}

static const char optstring[] = "";
static const struct option longopts[] = {
	{
		.name = "help",
		.has_arg = no_argument,
		.val = 'H',
	},
	{
		.name = "sender",
		.has_arg = required_argument,
		.val = 'S',
	},
	{
		.name = "port",
		.has_arg = required_argument,
		.val = 'P',
	},
	{
		.name = "bytes",
		.has_arg = required_argument,
		.val = 'M',
	},
	{
		.name = "buf-size",
		.has_arg = required_argument,
		.val = 'B',
	},
	{
		.name = "vsk-size",
		.has_arg = required_argument,
		.val = 'V',
	},
	{
		.name = "rcvlowat",
		.has_arg = required_argument,
		.val = 'R',
	},
	{},
};

static void usage(void)
{
	printf("Usage: ./vsock_perf [--help] [options]\n"
	       "\n"
	       "This is benchmarking utility, to test vsock performance.\n"
	       "It runs in two modes: sender or receiver. In sender mode, it\n"
	       "connects to the specified CID and starts data transmission.\n"
	       "\n"
	       "Options:\n"
	       "  --help			This message\n"
	       "  --sender   <cid>		Sender mode (receiver default)\n"
	       "                                <cid> of the receiver to connect to\n"
	       "  --port     <port>		Port (default %d)\n"
	       "  --bytes    <bytes>KMG		Bytes to send (default %d)\n"
	       "  --buf-size <bytes>KMG		Data buffer size (default %d). In sender mode\n"
	       "                                it is the buffer size, passed to 'write()'. In\n"
	       "                                receiver mode it is the buffer size passed to 'read()'.\n"
	       "  --vsk-size <bytes>KMG		Socket buffer size (default %d)\n"
	       "  --rcvlowat <bytes>KMG		SO_RCVLOWAT value (default %d)\n"
	       "\n", DEFAULT_PORT, DEFAULT_TO_SEND_BYTES,
	       DEFAULT_BUF_SIZE_BYTES, DEFAULT_VSOCK_BUF_BYTES,
	       DEFAULT_RCVLOWAT_BYTES);
	exit(EXIT_FAILURE);
}

static long strtolx(const char *arg)
{
	long value;
	char *end;

	value = strtol(arg, &end, 10);

	if (end != arg + strlen(arg))
		usage();

	return value;
}

int main(int argc, char **argv)
{
	unsigned long to_send_bytes = DEFAULT_TO_SEND_BYTES;	/*64k*/
	unsigned long rcvlowat_bytes = DEFAULT_RCVLOWAT_BYTES;	
	int peer_cid = -1;
	bool sender = false;

	while (1) {
		int opt = getopt_long(argc, argv, optstring, longopts, NULL);

		if (opt == -1)
			break;

		switch (opt) {
		case 'V': /* Peer buffer size. */
			vsock_buf_bytes = memparse(optarg);
			break;
		case 'R': /* SO_RCVLOWAT value. */
			rcvlowat_bytes = memparse(optarg);
			break;
		case 'P': /* Port to connect to. */
			port = strtolx(optarg);
			break;
		case 'M': /* Bytes to send. */
			to_send_bytes = memparse(optarg);
			break;
		case 'B': /* Size of rx/tx buffer. */
			buf_size_bytes = memparse(optarg);
			break;
		case 'S': /* Sender mode. CID to connect to. */
			peer_cid = strtolx(optarg);
			sender = true;
			break;
		case 'H': /* Help. */
			usage();
			break;
		default:
			usage();
		}
	}

	if (!sender)
		run_receiver(rcvlowat_bytes);
	else
		run_sender(peer_cid, to_send_bytes);

	return 0;
}



三、遇到的问题

问题1:Running postconf script ‘/usr/bin/python3 /home/yyh/kernel/qemu-8.0.2/scripts/symlink-install-tree.py’

NOTICE: You are using Python 3.6 which is EOL. Starting with v0.62.0, Meson will require Python 3.7 or newer

解决方法:

sudo apt-get install python3.7
which python3.7
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1
python3 --version

问题2:Traceback (most recent call last):File “/usr/lib/command-not-found”, line 28, in

from CommandNotFound import CommandNotFound
File “/usr/lib/python3/dist-packages/CommandNotFound/CommandNotFound.py”, line 19, in
from CommandNotFound.db.db import SqliteDatabase
File “/usr/lib/python3/dist-packages/CommandNotFound/db/db.py”, line 5, in
import apt_pkg
ModuleNotFoundError: No module named ‘apt_pkg’
参考:https://blog.csdn.net/qq_35191755/article/details/108199567

解决方法:

sudo apt-get remove --purge python-apt
sudo apt-get install -f -y python-apt

sudo cp /usr/lib/python3/dist-packages/apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.cpython-37m-x86_64-linux-gnu.so
sudo apt-get update

问题3:Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease

Could not resolve ‘security.ubuntu.com’
参考:https://blog.csdn.net/qq_29720657/article/details/109066682

解决方法

#vi /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
sudo service network-manager restart

问题4:qemu-system-aarch64: -device vhost-vsock-device,guest-cid=3: vhost-vsock: failed to open vhost device: No such device

参考:https://blog.csdn.net/kunyus/article/details/106986621

解决方法

运行下面命令,创建配置文件 /etc/modprobe.d/blacklist-vmware.conf。然后重启sudo reboot

sudo tee /etc/modprobe.d/blacklist-vmware.conf << EOF
blacklist vmw_vsock_virtio_transport_common
blacklist vmw_vsock_vmci_transport
EOF

原因

这是由于linux 检测到在 vmware 环境中运行时,会加载一些 vmware 的模块并使用 vsock 从而产生了冲突。

可以通过命令lsmod | grep vsock来查看哪些模块产生了冲突。
命令输出:
core@ubuntu20-dev:~$ lsmod | grep vsock
vmw_vsock_virtio_transport_common    32768  0
vmw_vsock_vmci_transport    32768  1
vsock                  36864  3 vmw_vsock_virtio_transport_common,vmw_vsock_vmci_transport
vmw_vmci               69632  2 vmw_balloon,vmw_vsock_vmci_transport

问题5:ubuntu设置共享文件夹时不显示解决方案

参考:
https://blog.csdn.net/qq_45953886/article/details/126020253

问题6:python升级

ERROR: Cannot use ‘/usr/bin/python’, Python >= 3.6 is required.
Use --python=/path/to/python to specify a supported Python.
参考:
https://blog.csdn.net/qq_38587510/article/details/104303929?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-104303929-blog-104701295.235%5Ev38%5Epc_relevant_default_base3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-104303929-blog-104701295.235%5Ev38%5Epc_relevant_default_base3&utm_relevant_index=10

问题7: ERROR: Cannot find Ninja

sudo apt update
sudo apt install ninja-build
#sudo dnf install ninja-build
#sudo pacman -S ninja

问题8:ERROR: You need at least GCC v7.4 or Clang v10.0 (or XCode Clang v12.0)

sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt update

sudo apt install gcc-8
sudo rm /usr/bin/gcc
sudo ln -s /usr/bin/gcc-8 /usr/bin/gcc

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yengi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值