第一篇文章描述了 如何使用預(yù)裝驅(qū)動(dòng)程序集成英偉達(dá) GPU 和網(wǎng)絡(luò)運(yùn)營(yíng)商 。
本文介紹了以下任務(wù):
清理預(yù)安裝的驅(qū)動(dòng)程序集成
使用自定義驅(qū)動(dòng)程序容器安裝網(wǎng)絡(luò)運(yùn)營(yíng)商
使用自定義驅(qū)動(dòng)程序容器安裝 GPU 操作員
NVIDIA 驅(qū)動(dòng)程序集成
預(yù)安裝的驅(qū)動(dòng)程序集成方法適用于需要簽名驅(qū)動(dòng)程序的邊緣部署,以實(shí)現(xiàn)安全和可測(cè)量的引導(dǎo)。當(dāng)邊緣節(jié)點(diǎn)具有不可變的操作系統(tǒng)時(shí),請(qǐng)使用驅(qū)動(dòng)程序容器方法。當(dāng)并非所有邊緣節(jié)點(diǎn)都有加速器時(shí),驅(qū)動(dòng)程序容器也適用。
清理預(yù)安裝的驅(qū)動(dòng)程序集成
首先,卸載以前的配置并重新啟動(dòng)以清除預(yù)安裝的驅(qū)動(dòng)程序。
刪除測(cè)試播客和網(wǎng)絡(luò)附件。
$ kubectl delete pod roce-shared-pod pod "roce-shared-pod" deleted $ kubectl delete macvlannetwork roce-shared-macvlan-network macvlannetwork.mellanox.com "roce-shared-macvlan-network" deleted
- 卸載網(wǎng)絡(luò)運(yùn)營(yíng)商掌舵圖。
$ helm delete -n network-operator network-operator release "network-operator" uninstalled
3 .卸載 MOFED 以刪除預(yù)安裝的驅(qū)動(dòng)程序和庫(kù)。
$ rmmod nvidia_peermem $ /etc/init.d/openibd stop Unloading HCA driver: [ OK ] $ cd ~/MLNX_OFED_LINUX-5.4-1.0.3.0-rhel7.9-x86_64 $ ./uninstall.sh
4 .拆下 GPU 測(cè)試盒。
$ kubectl delete pod cuda-vectoradd pod "cuda-vectoradd" deleted
5 .卸載英偉達(dá) Linux 驅(qū)動(dòng)程序。
$ ./NVIDIA-Linux-x86_64-470.57.02.run --uninstall
6 .拆下 GPU 操作器。
$ helm uninstall gpu-operator-1634173044
7 .重新啟動(dòng)。
$ sudo shutdown -r now
使用自定義驅(qū)動(dòng)程序容器安裝網(wǎng)絡(luò)運(yùn)營(yíng)商
本節(jié)介紹使用自定義驅(qū)動(dòng)程序容器安裝網(wǎng)絡(luò)運(yùn)營(yíng)商的步驟。
在容器映像中執(zhí)行的驅(qū)動(dòng)程序構(gòu)建腳本需要訪問(wèn)目標(biāo)內(nèi)核的內(nèi)核開(kāi)發(fā)包。在本例中,內(nèi)核開(kāi)發(fā)包是通過(guò) ApacheWeb 服務(wù)器提供的。
構(gòu)建容器后,將其上載到網(wǎng)絡(luò)運(yùn)營(yíng)商 Helm chart 可以從主機(jī)訪問(wèn)的存儲(chǔ)庫(kù)。
GPU 操作員將在下一節(jié)中使用相同的 web 服務(wù)器構(gòu)建自定義 GPU 操作員驅(qū)動(dòng)程序容器。
安裝 Apache web 服務(wù)器并啟動(dòng)它。
$ sudo firewall-cmd --state not running $ sudo yum install createrepo yum-utils httpd -y $ systemctl start httpd.service && systemctl enable httpd.service && systemctl status httpd.service ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2021-10-20 18:10:43 EDT; 4h 45min ago ...
- 創(chuàng)建上游 CentOS 7 基本軟件包存儲(chǔ)庫(kù)的鏡像。自定義包存儲(chǔ)庫(kù)在/ var 分區(qū)上需要 500 GB 的可用空間。請(qǐng)注意,將所有 CentOS Base 軟件包下載到 web 服務(wù)器可能需要 10 分鐘或更長(zhǎng)時(shí)間。
$ cd /var/www/html $ mkdir -p repos/centos/7/x86_64/os $ reposync -p /var/www/html/repos/centos/7/x86_64/os/ --repo=base --download-metadata -m
3 .將 Linux 內(nèi)核源文件復(fù)制到 web 服務(wù)器上的 Base packages 目錄中。本例假設(shè)使用 rpmbuild 將自定義內(nèi)核編譯為 RPM 。
$ cd repos/centos/7/x86_64/os $ sudo cp ~/rpmbuild/RPMS/x86_64/*.rpm .
網(wǎng)絡(luò)運(yùn)營(yíng)商需要以下文件:
- kernel-headers-${KERNEL_VERSION}
- kernel-devel-${KERNEL_VERSION}
確保 GPU 操作員有這些附加文件:
- gcc-${GCC_VERSION}
- elfutils-libelf.x86_64
- elfutils-libelf-devel.x86_64
$ for i in $(rpm -q kernel-headers kernel-devel elfutils-libelf elfutils-libelf-devel gcc | grep -v "not installed"); do ls $i*; done
kernel-headers-3.10.0-1160.42.2.el7.custom.x86_64.rpm
kernel-devel-3.10.0-1160.42.2.el7.custom.x86_64.rpm
elfutils-libelf-0.176-5.el7.x86_64.rpm
elfutils-libelf-devel-0.176-5.el7.x86_64.rpm
gcc-4.8.5-44.el7.x86_64.rpm
4 .瀏覽到 web 存儲(chǔ)庫(kù)以確保可通過(guò) HTTP 訪問(wèn)該存儲(chǔ)庫(kù)。
$ elinks http://localhost/repos/centos/7/x86_64/os --dump Index of /repos/centos/7/x86_64/os [1][ICO] [2]Name [3]Last modified [4]Size [5]Description -------------------------------------------------------------------------- [6][PARENTDIR] [7]Parent Directory - [8][DIR] [9]base/ 2021-10-21 22:55 - [10][DIR] [11]extras/ 2021-10-02 00:29 - -------------------------------------------------------------------------- References Visible links 2. http://localhost/repos/centos/7/x86_64/os/?C=N;O=D 3. http://localhost/repos/centos/7/x86_64/os/?C=M;O=A 4. http://localhost/repos/centos/7/x86_64/os/?C=S;O=A 5. http://localhost/repos/centos/7/x86_64/os/?C=D;O=A 7. http://localhost/repos/centos/7/x86_64/ 9. http://localhost/repos/centos/7/x86_64/os/base/ 11. http://localhost/repos/centos/7/x86_64/os/extras/
5.MOFED 驅(qū)動(dòng)程序容器映像是根據(jù) Github 上mellanox/ofed-docker存儲(chǔ)庫(kù)中的源代碼構(gòu)建的。克隆 ofed docker 存儲(chǔ)庫(kù)。
$ git clone https://github.com/Mellanox/ofed-docker.git
$ cd ofed-docker/
6 .為自定義驅(qū)動(dòng)程序容器創(chuàng)建生成目錄。
$ mkdir centos
$ cd centos/
7 .創(chuàng)建 Dockerfile ,將 MOFED 依賴項(xiàng)和源存檔安裝到 CentOS 7.9 基本映像中。指定 MOFED 和 CentOS 版本。
$ sudo cat << EOF | tee Dockerfile
FROM centos:centos7.9.2009 ARG D_OFED_VERSION="5.4-1.0.3.0"
ARG D_OS_VERSION="7.9"
ARG D_OS="rhel${D_OS_VERSION}"
ENV D_OS=${D_OS}
ARG D_ARCH="x86_64"
ARG D_OFED_PATH="MLNX_OFED_LINUX-${D_OFED_VERSION}-${D_OS}-${D_ARCH}"
ENV D_OFED_PATH=${D_OFED_PATH} ARG D_OFED_TARBALL_NAME="${D_OFED_PATH}.tgz"
ARG D_OFED_BASE_URL="https://www.mellanox.com/downloads/ofed/MLNX_OFED-${D_OFED_VERSION}"
ARG D_OFED_URL_PATH="${D_OFED_BASE_URL}/${D_OFED_TARBALL_NAME}" ARG D_WITHOUT_FLAGS="--without-rshim-dkms --without-iser-dkms --without-isert-dkms --without-srp-dkms --without-kernel-mft-dkms --without-mlnx-rdma-rxe-dkms"
ENV D_WITHOUT_FLAGS=${D_WITHOUT_FLAGS} # Download and extract tarball
WORKDIR /root
RUN yum install -y curl && (curl -sL ${D_OFED_URL_PATH} | tar -xzf -) RUN yum install -y atk \ cairo \ ethtool \ gcc-gfortran \ git \ gtk2 \ iproute \ libnl3 \ libxml2-python \ lsof \ make \ net-tools \ numactl-libs \ openssh-clients \ openssh-server \ pciutils \ perl \ python-devel \ redhat-rpm-config \ rpm-build \ tcl \ tcsh \ tk \ wget ADD ./entrypoint.sh /root/entrypoint.sh ENTRYPOINT ["/root/entrypoint.sh"]
EOF
8 .修改 ofed docker 存儲(chǔ)庫(kù)中包含的 RHEL entrypoint.sh 腳本,以從 web 服務(wù)器安裝自定義內(nèi)核源程序包。在_install_prerequsities()函數(shù)中指定 web 服務(wù)器上base/Packages目錄的路徑。
在本例中, 10.150.168.20 是本節(jié)前面創(chuàng)建的 web 服務(wù)器 IP 地址。
$ cp ../rhel/entrypoint.sh .
$ cat entrypoint.sh
...
# Install the kernel modules header/builtin/order files and generate the kernel version string.
_install_prerequisites() { echo "Installing dependencies" yum -y --releasever=7 install createrepo elfutils-libelf-devel kernel-rpm-macros numactl-libs initscripts grubby linux-firmware libtool echo "Installing Linux kernel headers..." rpm -ivh http://10.150.168.20/repos/centos/7/x86_64/os/base/Packages/kernel-3.10.0-1160.45.1.el7.custom.x86_64.rpm rpm -ivh http://10.150.168.20/repos/centos/7/x86_64/os/base/Packages/kernel-devel-3.10.0-1160.45.1.el7.custom.x86_64.rpm rpm -ivh http://10.150.168.20/repos/centos/7/x86_64/os/base/Packages/kernel-headers-3.10.0-1160.45.1.el7.custom.x86_64.rpm # Prevent depmod from giving a WARNING about missing files touch /lib/modules/${KVER}/modules.order touch /lib/modules/${KVER}/modules.builtin depmod ${KVER}
...
9OFED 驅(qū)動(dòng)程序容器從主機(jī)文件系統(tǒng)裝載一個(gè)目錄以共享驅(qū)動(dòng)程序文件。創(chuàng)建目錄。
$ mkdir -p /run/mellanox/drivers
10 將新的 CentOS 驅(qū)動(dòng)程序映像上載到注冊(cè)表。此示例使用 NGC 專用注冊(cè)表。登錄到注冊(cè)表。
$ sudo yum install -y podman $ sudo podman login nvcr.io
Username: $oauthtoken
Password: *****************************************
Login Succeeded!
11 使用 Podman 構(gòu)建驅(qū)動(dòng)程序容器映像并將其推送到注冊(cè)表。
$ sudo podman build --no-cache --tag nvcr.io/nv-ngc5g/mofed-5.4-1.0.3.0:centos7-amd64 .
12 標(biāo)記圖像并將其推送到注冊(cè)表。
$ sudo podman images nvcr.io | grep mofed
nvcr.io/nv-ngc5g/mofed-5.4-1.0.3.0 centos7-amd64 d61e555bddda 2 minutes ago 1.13 GB
13 覆蓋英偉達(dá)網(wǎng)絡(luò)運(yùn)營(yíng)商頭盔圖中包含的 Value.YAML 文件,以安裝自定義驅(qū)動(dòng)程序映像。指定自定義驅(qū)動(dòng)程序容器的映像名稱、存儲(chǔ)庫(kù)和版本。
$ cat << EOF | sudo tee roce_shared_values_driver.yaml nfd: enabled: false
deployCR: true
ofedDriver: deploy: true image: mofed repository: nvcr.io/nv-ngc5g version: 5.4-1.0.3.0
sriovDevicePlugin: deploy: false
rdmaSharedDevicePlugin: deploy: true resources: - name: rdma_shared_device_a vendors: [15b3] deviceIDs: [101d] ifNames: [ens13f0]
EOF
14 安裝英偉達(dá)網(wǎng)絡(luò)運(yùn)營(yíng)商的新價(jià)值。
$ helm install -f ./roce_shared_values_driver.yaml -n network-operator --create-namespace --wait network-operator mellanox/network-operator
15 查看網(wǎng)絡(luò)運(yùn)營(yíng)商部署的 POD 。 MOFED 吊艙應(yīng)處于運(yùn)行狀態(tài)。這是自定義驅(qū)動(dòng)程序容器。請(qǐng)注意,在啟動(dòng) pod 之前編譯驅(qū)動(dòng)程序可能需要幾分鐘的時(shí)間。
$ kubectl -n nvidia-network-operator-resources get pods
NAME READY STATUS RESTARTS AGE
cni-plugins-ds-zr9kf 1/1 Running 0 10m
kube-multus-ds-w57rz 1/1 Running 0 10m
mofed-centos7-ds-cbs74 1/1 Running 0 10m
rdma-shared-dp-ds-ch8m2 1/1 Running 0 2m27s
whereabouts-z947f 1/1 Running 0 10m
16 驗(yàn)證主機(jī)上是否加載了 MOFED 驅(qū)動(dòng)程序。
$ lsmod | egrep '^ib|^mlx|^rdma'
rdma_ucm 27022 0 rdma_cm 65212 1 rdma_ucm
ib_ipoib 124872 0 ib_cm 53085 2 rdma_cm,ib_ipoib
ib_umad 27744 0 mlx5_ib 384793 0 mlx5_core 1360822 1 mlx5_ib
ib_uverbs 132833 2 mlx5_ib,rdma_ucm
ib_core 357959 8 rdma_cm,ib_cm,iw_cm,mlx5_ib,ib_umad,ib_uverbs,rdma_ucm,ib_ipoib
mlx_compat 55063 11 rdma_cm,ib_cm,iw_cm,auxiliary,mlx5_ib,ib_core,ib_umad,ib_uverbs,mlx5_core,rdma_ucm,ib_ipoib
mlxfw 22321 1 mlx5_core
17 驅(qū)動(dòng)程序容器的根文件系統(tǒng)應(yīng)綁定到主機(jī)上的/run/mellanox/drivers目錄。
$ ls /run/mellanox/drivers
anaconda-post.log bin boot dev etc home host lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
使用自定義驅(qū)動(dòng)程序容器安裝 GPU 操作員
本節(jié)介紹使用自定義驅(qū)動(dòng)程序容器安裝 GPU 操作符的步驟。
與網(wǎng)絡(luò)運(yùn)營(yíng)商一樣, GPU 運(yùn)營(yíng)商容器執(zhí)行的驅(qū)動(dòng)程序構(gòu)建腳本需要訪問(wèn)目標(biāo)內(nèi)核的開(kāi)發(fā)包。
本例使用的 web 服務(wù)器與上一節(jié)中向網(wǎng)絡(luò)運(yùn)營(yíng)商交付開(kāi)發(fā)包的 web 服務(wù)器相同。
構(gòu)建容器后,將其上載到 GPU 操作員 Helm chart 可以從主機(jī)訪問(wèn)的存儲(chǔ)庫(kù)。與網(wǎng)絡(luò)運(yùn)營(yíng)商示例一樣, GPU 運(yùn)營(yíng)商也使用 NGC 上的專用注冊(cè)表。
構(gòu)建自定義驅(qū)動(dòng)程序容器。
$ cd ~
$ git clone https://gitlab.com/nvidia/container-images/driver.git
$ cd driver/centos7
2 .更新 CentOS Dockerfile 以使用驅(qū)動(dòng)程序版本 470.74 。注釋掉未使用的參數(shù)。
$ grep ARG Dockerfile ARG BASE_URL=http://us.download.nvidia.com/XFree86/Linux-x86_64
#ARG BASE_URL=https://us.download.nvidia.com/tesla
ARG DRIVER_VERSION=470.74
ARG DRIVER_TYPE=passthrough
ARG VGPU_LICENSE_SERVER_TYPE=FNE
ARG PUBLIC_KEY=''
#ARG PUBLIC_KEY=empty
ARG PRIVATE_KEY
3 .構(gòu)建 GPU 驅(qū)動(dòng)程序容器映像并將其推送到 NGC 。
$ sudo podman build --no-cache --tag nvcr.io/nv-ngc5g/driver:470.74-centos7 .
4 .查看 GPU 驅(qū)動(dòng)程序容器圖像。
$ podman images nvcr.io | grep 470
nvcr.io/nv-ngc5g/driver 470.74-centos7 630f0f8e77f5 2 minutes ago 1.28 GB
5 .驗(yàn)證為網(wǎng)絡(luò)運(yùn)營(yíng)商安裝創(chuàng)建的自定義存儲(chǔ)庫(kù)中是否存在以下文件:
- elfutils-libelf.x86_64
- elfutils-libelf-devel.x86_64
- kernel-headers-${KERNEL_VERSION}
- kernel-devel-${KERNEL_VERSION}
- gcc-${GCC_VERSION}
編譯自定義內(nèi)核映像的驅(qū)動(dòng)程序需要這些文件。
$ cd /var/www/html/repos/centos/7/x86_64/os/base/Packages/ $ for i in $(rpm -q kernel-headers kernel-devel elfutils-libelf elfutils-libelf-devel gcc | grep -v "not installed"); do ls $i*; done
kernel-headers-3.10.0-1160.45.1.el7.custom.x86_64.rpm
kernel-devel-3.10.0-1160.45.1.el7.custom.x86_64.rpm
elfutils-libelf-0.176-5.el7.x86_64.rpm
elfutils-libelf-devel-0.176-5.el7.x86_64.rpm
gcc-4.8.5-44.el7.x86_64.rpm
6 .與網(wǎng)絡(luò)運(yùn)營(yíng)商不同, GPU 運(yùn)營(yíng)商使用自定義的 Yum 存儲(chǔ)庫(kù)配置文件。創(chuàng)建引用自定義鏡像存儲(chǔ)庫(kù)的 Yum repo 文件。
$ cd /var/www/html/repos $ cat << EOF | sudo tee custom-repo.repo [base]
name=CentOS Linux $releasever - Base
baseurl=http://10.150.168.20/repos/centos/$releasever/$basearch/os/base/
gpgcheck=0
enabled=1
EOF
7.GPU 運(yùn)算符使用 Kubernetes ConfigMap 來(lái)配置自定義存儲(chǔ)庫(kù)。 ConfigMap 必須在gpu-operator-resources命名空間中可用。創(chuàng)建名稱空間和 ConfigMap 。
$ kubectl create ns gpu-operator-resources $ kubectl create configmap repo-config -n gpu-operator-resources --from-file=/var/www/html/repos/custom-repo.repo
configmap/repo-config created $ kubectl describe cm -n gpu-operator-resources repo-config Name: repo-config
Namespace: gpu-operator-resources
Labels:
Annotations: Data
====
custom-repo.repo:
----
[base]
name=CentOS Linux $releasever - Base
baseurl=http://10.150.168.20/repos/centos/$releasever/$basearch/os/base/
gpgcheck=0
enabled=1
8 .安裝 GPU 操作員舵圖。指定自定義存儲(chǔ)庫(kù)位置、自定義驅(qū)動(dòng)程序版本以及自定義驅(qū)動(dòng)程序映像名稱和位置。
$ helm install nvidia/gpu-operator --generate-name --set driver.repoConfig.configMapName=repo-config --set driver.repoConfig.destinationDir=/etc/yum.repos.d --set driver.image=driver --set driver.repository=nvcr.io/nv-ngc5g --set-string driver.version="470.74" --set toolkit.version=1.7.1-centos7 --set operator.defaultRuntime=crio
9 查看已部署的吊艙。
$ kubectl get pods -n gpu-operator-resources
NAME READY STATUS RESTARTS AGE
gpu-feature-discovery-r6kq6 1/1 Running 0 3m33s
nvidia-container-toolkit-daemonset-62pbj 1/1 Running 0 3m33s
nvidia-cuda-validator-ljd5l 0/1 Completed 0 119s
nvidia-dcgm-9nsfx 1/1 Running 0 3m33s
nvidia-dcgm-exporter-zm82v 1/1 Running 0 3m33s
nvidia-device-plugin-daemonset-bp66r 1/1 Running 0 3m33s
nvidia-device-plugin-validator-8pbmv 0/1 Completed 0 108s
nvidia-driver-daemonset-4tx24 1/1 Running 0 3m33s
nvidia-mig-manager-kvcgc 1/1 Running 0 3m32s
nvidia-operator-validator-g9xz5 1/1 Running 0 3m33s
10 驗(yàn)證驅(qū)動(dòng)程序是否已加載。
$ lsmod | grep nvidia
nvidia_modeset 1195268 0 nvidia_uvm 995356 0 nvidia 35237551 114 nvidia_modeset,nvidia_uvm
drm 456166 5 ast,ttm,drm_kms_helper,nvidia
11 從驅(qū)動(dòng)程序守護(hù)程序盒運(yùn)行 nvidia smi 。
Defaulted container "nvidia-driver-ctr" out of: nvidia-driver-ctr, k8s-driver-manager (init)
Thu Oct 28 02:37:50 2021 +-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.74 Driver Version: 470.74 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA A100-PCI... On | 00000000:23:00.0 Off | 0 |
| N/A 25C P0 32W / 250W | 0MiB / 40536MiB | 0% Default |
| | | Disabled |
+-------------------------------+----------------------+----------------------+
| 1 NVIDIA A100-PCI... On | 00000000:E6:00.0 Off | 0 |
| N/A 27C P0 32W / 250W | 0MiB / 40536MiB | 0% Default |
| | | Disabled |
+-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
啟用 GPUnDeID-RDMA 的英偉達(dá)對(duì)等存儲(chǔ)器驅(qū)動(dòng)器不是自動(dòng)構(gòu)建的。
重復(fù)此過(guò)程以構(gòu)建自定義 nvidia peermem 驅(qū)動(dòng)程序容器。
對(duì)于 GPU 運(yùn)營(yíng)商中的 nvidia peermem 安裝程序尚不支持的任何 Linux 操作系統(tǒng),都需要此附加步驟。
英偉達(dá)加速器的未來(lái)
NVIDIA 加速器有助于在傳感器數(shù)據(jù)呈指數(shù)級(jí)增長(zhǎng)的情況下,對(duì)未來(lái)的邊緣 AI 投資進(jìn)行驗(yàn)證。 NVIDIA 運(yùn)營(yíng)商是云本地軟件,可簡(jiǎn)化 Kubernetes 上的加速器部署和管理。運(yùn)營(yíng)商支持流行的 Kubernetes 開(kāi)箱即用平臺(tái),并且可以定制以支持替代平臺(tái)。
關(guān)于作者
Jacob Liberman 是 NVIDIA 企業(yè)和邊緣加速集團(tuán)的產(chǎn)品經(jīng)理。他利用 20 多年的技術(shù)計(jì)算經(jīng)驗(yàn)提供高性能、云計(jì)算原生邊緣人工智能解決方案。此前,他曾在紅帽、 AMD 和戴爾擔(dān)任產(chǎn)品管理和工程職務(wù)。
審核編輯:法人
-
傳感器
+關(guān)注
關(guān)注
2551文章
51099瀏覽量
753606 -
NVIDIA
+關(guān)注
關(guān)注
14文章
4986瀏覽量
103066
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論