LCOV - code coverage report
Current view: top level - legacy/ascend910/pub_inc - peterson_lock.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 7 7
Test Date: 2026-07-28 12:11:00 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #ifndef PETERSON_LOCK_H
      12              : #define PETERSON_LOCK_H
      13              : 
      14              : #include <string>
      15              : #include <thread>
      16              : #include <atomic>
      17              : #include <hccl/hccl_types.h>
      18              : #include "hccl_common.h"
      19              : #include "mem_device_pub.h"
      20              : 
      21              : /**
      22              :  * 这里实现Peterson算法来实现host侧与device侧的互斥访问
      23              :  *
      24              :  * 背景:host侧与device可以通过H2D/D2H等API来进行共享内存访问,
      25              :  *       那么这两者之间无法对共享变量使用类似于CAS的机制,因此不能基于
      26              :  *       原子修改类API的方式实现锁,所以这里基于Peterson算法实现,
      27              :  *       paper参考:https://zoo.cs.yale.edu/classes/cs323/doc/Peterson.pdf
      28              :  *
      29              :  * 依赖:Peterson算法虽然不依赖原子操作,但是依赖读写内存序,因此需要添加内存屏障
      30              :  *       来避免编译器与CPU的乱序执行
      31              :  *
      32              :  * 限制:目前实现只支持单个Host线程与单个Device线程互斥访问,不支持Host/Device侧多线程访问,
      33              :  *       如需单侧多线程访问请先使用std::mutex或者pthread_spinlock_t保证互斥,再使用该锁
      34              :  *
      35              :  * 内存布局:
      36              :  *      [u32 turn] [u32 hostFlag] [u32 deviceFlag]
      37              :  */
      38              : namespace hccl {
      39              : class PetersonLock {
      40              : public:
      41              :     static constexpr u64 DEFAULT_LOCK_TIMEOUT_SEC = 60; /* 默认的超时时间, 60s */
      42              : 
      43              :     /* Host侧对象构造函数,在Init()中会进行Device侧内存申请 */
      44              :     explicit PetersonLock(u64 timeoutSec);
      45              :     /* Device侧对象构造函数,devPtr是在Host申请的设备侧内存地址 */
      46              :     PetersonLock(void *devPtr, u64 timeoutSec);
      47              :     ~PetersonLock();
      48              : 
      49              :     HcclResult Init();
      50              :     HcclResult DeInit();
      51              : 
      52              :     /* 目前该接口只服务于传递地址给Device侧,所以直接返回u64而不是指针 */
      53              :     u64 GetDevMemAddr() const;
      54              : 
      55              :     HcclResult Lock();
      56              :     HcclResult Unlock();
      57              : 
      58              :     /* 显式禁用所有copy、move构造函数,因为锁不可复制,不可移动 */
      59              :     PetersonLock(const PetersonLock &) = delete;
      60              :     PetersonLock(PetersonLock &&) = delete;
      61              :     PetersonLock& operator=(const PetersonLock &) = delete;
      62              :     PetersonLock& operator=(PetersonLock &&) = delete;
      63              : private:
      64              :     HcclResult AllocDeviceMem();
      65              : 
      66              :     HcclResult WriteSelfFlag(u32 selfFlag);
      67              :     HcclResult WriteTurn();
      68              :     HcclResult ReadPeerFlag(u32 &peerFlag);
      69              :     HcclResult ReadTurn(u32 &peerTurn);
      70              : 
      71              :     static constexpr size_t MIN_SHM_LEN = 32; /* 最小的共享内存大小 */
      72              :     enum class Type : int {
      73              :         HOST = 0,
      74              :         DEVICE = 1
      75              :     };
      76              : 
      77              :     static constexpr u32 TURN_FOR_HOST    = 1;
      78              :     static constexpr u32 TURN_FOR_DEVICE  = 0;
      79              :     static constexpr u32 FLAG_LOCK   = 1;    /* 获取锁 */
      80              :     static constexpr u32 FLAG_UNLOCK = 0;    /* 释放锁 */
      81              : 
      82         1198 :     void MemFence() const
      83              :     {
      84              :         /* 内存屏障,即阻止编译器重排变量读写,也阻止CPU重排变量读写 */
      85              :         std::atomic_thread_fence(std::memory_order_seq_cst);
      86         1198 :     }
      87              : 
      88         1320 :     void Wait() const
      89              :     {
      90              :         /* 无事可做暂时释放CPU */
      91         1320 :         sched_yield();
      92         1320 :     }
      93              : 
      94              :     size_t size_ = 0;
      95              :     Type type_ = Type::HOST;
      96              :     std::string typeName_;
      97              :     u64 timeout_;
      98              :     DeviceMem devMem_;
      99              :     u32 myTurn_;
     100              : 
     101              :     /*
     102              :      * 这里变量使用volatile修饰,是为了Device直接读写内存数据,而不是CPU cache
     103              :      */
     104              :     volatile u32 *turn_ = nullptr;
     105              :     volatile u32 *hostFlag_ = nullptr;
     106              :     volatile u32 *deviceFlag_ = nullptr;
     107              : };
     108              : /**
     109              :  * 使用RAII特性使用PetersonLock,在该对象构造时加锁,析构时释放锁
     110              :  * 因为获取锁有可能失败,所以要调用IsLockFailed()去检查,只有加锁成功才能继续往下执行
     111              :  */
     112              : class PetersonLockGuard {
     113              : public:
     114              :     explicit PetersonLockGuard(PetersonLock *lock);
     115              :     ~PetersonLockGuard();
     116              : 
     117          200 :     bool IsLockFailed() const
     118              :     {
     119          200 :         return lockFailed_;
     120              :     }
     121              : 
     122              :     /* 显式禁用所有copy、move构造函数,因为锁不可复制,不可移动 */
     123              :     PetersonLockGuard(const PetersonLockGuard &) = delete;
     124              :     PetersonLockGuard(PetersonLockGuard &&) = delete;
     125              :     PetersonLockGuard& operator=(const PetersonLockGuard &) = delete;
     126              :     PetersonLockGuard& operator=(PetersonLockGuard &&) = delete;
     127              : private:
     128              :     PetersonLock *lock_ = nullptr;
     129              :     bool lockFailed_ = false;
     130              : };
     131              : }
     132              : 
     133              : #endif
        

Generated by: LCOV version 2.0-1