DOCA: Basic Manual & Running allreduce

최승혁·2022년 8월 29일
0

DOCA Architecture

1. DOCA Device

DOCA device 구성 요소

  • ECPF: DOCA HW dev
  • Representor in DPU: DOCA Remote dev
  • Function in Host
  • DOCA dev: DOCA HW dev

DOCA dev

(1) ECPF

DOCA에서는 2개의 Physical Device를 제공한다. 명명은 ECPF로 하고 있으며, NIC에 DOCA 이미지 설치 시 기본적으로 Device가 제공되고 있다.

ECPF

(2) Device in Host

NIC에서와 같이 2개의 Device가 제공되어 있다. mst start 명령어를 통해, device가 생성되며, NIC의 HW device와 연결되어 있다.

Doca device in node3

Representor&Function

ECPF가 Host에 접근하기 위한 수단으로 2개의 ECPF에 대해 기본적으로 2개의 Representor가 존재한다. 그리고 Host가 ECPF에 접근하기 위한 수단으로 2개의 PF이 존재한다.

NIC과 Host는 서로의 HW device와 소통하기 위해 각기 다른 수단을 두고 있다. Host의 예로는 Physical Function, Virtual Function, Scalable Function이 있으며, 각각의 명명 규칙이 있다.

(1) Host Function

pf + pf num ( vf/sf일 경우) + vf/sf + vf/sf num

  • pf0: Physical function임을 나타내고, 0은 PF의 인덱스를 나타낸다.
  • pf0vf0: pf0과 연결된 vf0

function

(2) NIC Representor

pf + pf num (vf/sf일 경우) + vf/sf + vf/sf num

  • hpf0: host의 pf0과 소통하는 representor
  • hpf0vf0: host pf0과 연결되어 생성된 vf0
  • en3f0pf*sh*: pf*과 연결되어 생성된 sf*

representor

2. Mode

3. Virtual Functions

SR-IOV는 PCIe device가 PCIe bus를 통해 자신을 여러 개로 노출 시키는 것이다. 이 기능을 통해, 분리된 자원을 사용하는 device의 가상의 인스턴스를 생성할 수 있다.

VF(Virtual fuctions)는 Virtual 인스턴스(VM)와 소통할 수 있는 함수로, PF에 연결되는 추가적인 장치로 볼 수 있다. VF는 PF와 자원을 공유하고, port 또한 PF와 같다. 이를 NIC에서는 representor라고 명명한다.

생성

// Enable SR-IOV
host$ mlxconfig -y -d /dev/mst/mt41686_pciconf0 s SRIOV_EN=1 

// Set number of VFs
host$ mlxconfig -y -d /dev/mst/mt41686_pciconf0 s NUM_OF_VFS=X 
host$ echo X > /sys/class/net/<physical_function>/device/sriov_numvfs

생성 결과 예

vf example

vf example2

4. vSwitch&E-Switch

5. Scalable Functions

SF(Scalable fuctions or sub-fuctions)은 SR-IOV에서의 VF와 매우 비슷하다. SF 또한 IO virtualization 기능을 제공하며, Device에 직접 접근할 수 있고, PF와 공유되는 자원이다.

BlueField에서는 VF의 기능을 활용하기 위해, SF를 사용한다. SF는 VF보다 많은 기능을 지원하며, 특히 DPU에서 여러 서비스가 동시에 실행될 수 있다. SF는 Parent PCIe의 가벼운 function이기 때문에, Parent PCIe의 자원에 접근할 수 있으며 자신의 자원과 함수 또한 가지고 있다. 이는, SF는 전용 TX, RX queue를 가지고 있다는 뜻이다.

SF는 PCIe의 SR-IOV 기능과 공존하지만, SR-IOV를 설정할 필요는 없다. SF는 PF와 VF처럼 E-Switch representation를 지원한다. 또한, PCIe 레벨의 자원을 다른 SF 또는 parent PCIe function과 공유한다.

SF

생성

(1) Create
// create SF by adding a port of "pcisf"
// Each SF must have a unique number <sfnum>
/opt/mellanox/iproute2/sbin/mlxdevm port add pci/<pci_address> flavour pcisf pfnum <corresponding pfnum> sfnum <sfnum>

sf create

(2) Configure
// configure the hardware address, set trust mode to on, activate SF
/opt/mellanox/iproute2/sbin/mlxdevm port function set pci/<pci_address>/<sf_index>  hw_addr <MAC address> trust on state active

sf configure

(3) Deploy
// unbind SF from defualt config driver
// bind SF actual SF driver
echo mlx5_core.sf.<next_serial>  > /sys/bus/auxiliary/drivers/mlx5_core.sf/bind

// the way to know <next_serial>
$ devlink dev show

// output before creating, configuring, deploying the SF
pci/0000:03:00.0
pci/0000:03:00.1
auxiliary/mlx5_core.sf.2
auxiliary/mlx5_core.sf.3 

// output after creating, configuring, deploying the SF
pci/0000:03:00.0
pci/0000:03:00.1
auxiliary/mlx5_core.sf.2
auxiliary/mlx5_core.sf.3
auxiliary/mlx5_core.sf.4  

// <next_serial> number is 4
// to see the <sfnum> of each sub-function
cat /sys/bus/auxiliary/devices/mlx5_core.sf.<next_serial>/sfnum

// output
4 

sf deploy

sf add port

(+) inactive&delete

/opt/mellanox/iproute2/sbin/mlxdevm port function set pci/<pci_address>/<sf_index> state inactive
/opt/mellanox/iproute2/sbin/mlxdevm port del pci/<pci_address>/<sf_index>

실험 전 과정

1. Allreduce란?

선택한 operator를 다른 처리 장치에서 수행하여 결과를 전역으로 저장하여 데이터를 수집하게 도와주는 어플리케이션이다. 결국, 결과는 모든 처리 장치에 다시 배포된다.

Allreduce는 총 3단계로 이루어져 있다.

  1. 각 participant가 벡터를 전송한다.
  2. 각 participant는 다른 participant의 벡터를 수집한다.
  3. 각 participant는 수집한 벡터에 선택한 연산자를 수행한다.

일련의 allreduce을 각 participant들이 다른 연산을 수행하면, 복잡한 계산을 분산 작업할 수 있다. allreduce는 시뮬레이션이나 데이터 분석, 머신러닝과 같은 HPC 환경에서 병렬 어플리케이션으로 널리 사용된다.

Allreduce는 2가지 type을 지원한다.

  • Offloaded client: DPU에서 수행 중인 daemon에게 operation 요청만 보내는 host 프로세스가 수행된다. DPU에서 수행 중인 daemon은 host client를 대신하여 allreduce 알고리즘을 수행한다.
  • Non-offloaded client: allreduece 알고리즘을 자신이 직접 수행하는 host 프로세스를 수행

2. Allreduce 설계

어플리케이션은 다음 세 가지 항목을 측정하도록 설계되었다.

  • Offloaded거나 Non-offloaded 연산에 의해 작업이 소요되는 시간
  • Allreduce operation이 완료되기 전, client에 의해 matrix multiplication이 수행되는 시간
  • Matrix multiplication과 allreduce 연산이 병렬적로 수행된 총 런타임의 백분률

img

Allreduce에는 두 가지 타입의 프로세스가 있다.

  • Client: 벡터에 데이터를 채워 할당하고, daemon에게 벡터와 함께 request 요청을 보냄으로써 allreduce 연산을 초기화 한다.
  • Daemon: 연결된 모든 daemon과 client로부터 벡터를 수집하고, 전송 받은 벡터에 선택된 operation을 모두 수행한다. 그리고 결과를 다시 Client에게 재전송한다.

실험 구현

1. build

cd /opt/mellanox/doca/applications/
meson build
ninja -C build

빌드 할 앱은 meson_options.txt를 수정함으로써 지정 가능하다.

meson_option

2. Configure

  • NIC

image-20220721154131255

image-20220721154148944

image-20220721154200515

  • Host

image-20220721154236928

Running

image-20220721132122112

[Allreduce] running error #1

context 1

node 3 NIC에서 daemon 실행 시, localdomain으로 연결 요청 및 연결 요청 실패

image-20220725182436178

Code

  • connections_init() in allreduce_core.c

image-20220725200722843

connecting을 연결한 후 이후의 코드가 실행되지 않고 있다.

이를 통해, allreduce_ucx_connect() 함수에서 무한 루프가 돌지 않은지 의심할 수 있다.

  • allreduce_ucx_connect() in allreduce_core.c

image-20220725201338119

다음은 allreduce_ucx_connect() 함수 내부이다.

함수 내부에는 소켓을 설정하고 연결하는 코드와 이를 확인하기 위해 Active Message를 전송하는 부분이 있다.

여기서 Active Message가 연결을 확인할 때까지 polling하는 방식으로 대기하고 있다.

기존의 실행은 핑을 통해 연결이 됐음을 확인할 수 있었다.

하지만, Active Message Warning이 뜨며, 연결이 완료되지 않았었는데, 여기 Active Message를 통한 연결 확인이 되지 않아 무한 루프를 돌고 있는 것으로 추정된다.

또한 Warning이 뜨는 이유도 이와 관련하여 request Active Message를 전송함과 동시에 Ack Active Message를 전송하는 과정에서 출력되는 것으로 추정된다.

  • am_send() in allreduce_ucx.c

image-20220725201845877

다음은 am_send() 함수의 내부이며, Active Message를 전송하고, 결과값을 통해 request_process 함수를 수행한다.

ucp_am_send_nbx함수는 DOCA documentation을 살펴보면 다음과 같은 기능을 한다.

  1. Parameters
    • *connection: connect to send the AM. (end point)
    • am_id: AM identifier
    • *header: pointer to a user-defined header for an AM
    • header_length: length of the header to send
    • *buffer: pointer to the AM payload
    • length: number of elements in the payload buffer.
    • param: additional parameters
  1. 기능: returns a status pointer to check the operation's status, NULL means success.
  • request_process() in ~.c

image-20220725203359866

다음은 request_process() 함수의 내부이다. 각 if문은 예외 처리를 담당하며, 첫 번째 If문에서 연결 성공 시, 콜백 함수를 호출하며 함수를 종료하게 된다.

이 함수를 통해 알 수 있는 것은 request 요청이 성공 적이지 않아(ptr_status != NULL) 0으로 return되어 종료되고 있다.

[Allreduce] running error #2

Flag

  • -a: 다른 daemon과 상호작용하기 위해 필수, offloaded 클라이언트에게는 연산을 수행할 daemon의 주소를 필수로 입력해야 함. daemon이나 non-offloaded 클라이언트에게 주소가 입력되면, 연산의 수행 결과를 공유한다.
  • -m: non-offloaded 모드를 기본으로 수행

context 2

node 4 host와 node 3 NIC의 연결 요청 상황,

둘 다 연결은 되나 host에서 NIC으로 벡터를 보낸 후, offload 연산 수행이 안 됨

image-20220726132230734

image-20220726132255123

context 3

node 4 host와 node 3 NIC의 연결 요청 (offloaded 모드 지정)

기존 node 3 host와 연결 요청에서처럼, UCP warning

tcpdump에서는 계속해서 NIC이 연결 요청을 보내는 중

image-20220726132428998

image-20220726132406767

context 4

node 4 host에서 daemon으로 실행 시,

성공적으로 연결 후, 클라이언트가 없어 종료

image-20220726132755384

context 5

context 2 상황에서 host와 nic 둘 다 client role로 수행하니 연결 후 수행 완료됨.

image-20220726133440390

image-20220726133557675

context 6

node 4 daemon, node 3 NIC client로 수행하니 context2와 동일한 상황

context 7

node 4 daemon, node 3 NIC client 수행 (offloaded mode),

수행 완료

image-20220726155752382

image-20220726155809968

정리

contextrolemoderolemode결과
1daemonlocal domain error
2clientnon-offloaddaemon배리어 O, 연산 수행 X
3clientoffloaddaemonUCX WARN
4daemongood
5clientnon-offloadclientnon-offloadgood
6daemonclientnon-offload배리어 O, 연산 수행 x
7daemonclientoffloadgood

context 5의 경우 서로 non-offloaded 연산을 수행 후 결과를 공유하는 것으로 추정

context 2와 6의 경우, 연결 하나 non-offload 연산이라 수행 X 인 것으로 추정

4와 7의 경우 잘 됨

context 1, 3과 기존의 문제를 통해 NIC의 통신 문제 추정

code

image-20220726195106319

image-20220726195134940

다음은 node 4와 node 3의 NIC에서 daemon을 수행했을 때이다.

node 4의 경우에는 connecting 시도 없이 바로 successful이라는 로그가 뜬다.

하지만, node 3 NIC에서는 local domain으로 연결 시도 중 실패 오류가 난다.

이를 중점으로 코드를 보았다.

  • main() in allreduce.c

image-20220726195345288

다음은 allreduce의 메인 함수이다.

allreduce_init() 함수에서 연결을 시도하며, 수행이 완료된 후에 "Successfully conected .." 로그가 등장하게 된다.

  • allreduce_init() in allreduce_core.c

image-20220726195607603

다음은 allreduce_init() 함수이다.

간략하게 설명하면 dest_addresses_init() 함수에서 큐를 생성하여 목적지 엔트리 enqueue 함으로써 연결을 시도 할 목적지를 설정한다.

그리고 allreduce_ucx_init() 함수에서 프로그램 전역에서 사용할 context와 callback을 생성한다.

마지막으로 communication_init()함수에서 연결을 설정한다. 이때, daemon이나 non-offloaded 클라이언트의 경우 리스너를 먼저 생성한 뒤 연결을 설정한다.

  • connections_init() in allreduce_core.c

image-20220726200530738

다음 connections_init() 함수를 살펴보면, 큐에서 params를 통해 연결 목적지에 연결하는 모습이다.

여기서 알 수 있는 것은 node 4의 daemon은 큐가 비어있어 연결을 따로 수행하지 않고 daemon이 동작했다는 것이다. node 3의 NIC에서는 -a 를 이용한 peer 설정이 없어도 큐를 통해 연결 설정을 시도했다.

dest_addresses_init() in allreduce_core.c

running

  • Daemon
// env 설정
export UCX_NET_DEVICES=enp3s0f0s0,mlx5_2:1


// 메모리 limit 해제
Ulimit –l unlimited

// app 실행
/opt/mellanox/doca/applications/allreduce/bin/doca_allreduce -r daemon -t 34001 -i 1 -b 1 -c 1 -l 4
  • Client
// app 실행
/opt/mellanox/doca/applications/allreduce/bin/doca_allreduce -r client -m offloaded -t 35001 -a 192.168.101.1:34001 -i 1 -b 1 -l 4

output

image
image

  • image-20220727122220005
profile
그냥 기록하는 블로그

0개의 댓글