openMPM源码分析(二)

test/sync_test/src/c66x/main.c
接着昨天的main.c后面的内容。
  1. 函数 int32_t sync_test_shmem_create(int32_t num_dsps);
    1. 创建一个不大于4K(0x0000 1000)的内存空间,起始地址为0xA000 0000。
    2. NOTE:这里的0xA000 0000正好是MAR160所管理的内存范围的起始地址。
  2. 函数 int32_t sync_test_barr_create(int32_t num_dsps);
    1. 创建一个不大于4K(0x0000 1000)的内存空间作为barrier,起始地址为0xA000 1000。
    2. NOTE:Memory Barrier简介( http://name5566.com/4535.html):
      1. 为了提升程序运行时的性能,程序在运行时内存实际的访问顺序和程序代码编写的访问顺序不一定一致,也就是内存乱序访问。
      2. 乱序访问主要有两种情况:编译器优化导致的乱序访问、多CPU间交互引起的内存乱序访问。
      3. 对于前者:Linux内核提供函数barrier()来保证其之前的内存访问先于其之后的内存访问。
        #define barrier() __asm__ __volatile__("" ::: "memory");
      4. 对于后者, 在多 CPU 的机器上,问题又不一样了。每个 CPU 都存在 cache(cache 主要是为了弥补 CPU 和内存之间较慢的访问速度),当一个特定数据第一次被特定一个 CPU 获取时,此数据显然不在 CPU 的 cache 中(这就是 cache miss)。此 cache miss 意味着 CPU 需要从内存中获取数据(这个过程需要 CPU 等待数百个周期),此数据将被加载到 CPU 的 cache 中,这样后续就能直接从 cache 上快速访问。当某个 CPU 进行写操作时,它必须确保其他的 CPU 已经将此数据从它们的 cache 中移除(以便保证一致性),只有在移除操作完成后此 CPU 才能安全的修改数据。显然,存在多个 cache 时,我们必须通过一个 cache 一致性协议来避免数据不一致的问题,而这个通讯的过程就可能导致乱序访问的出现,也就是这里说的运行时内存乱序访问。
  3. 函数 int32_t sync_test_lock_create(int32_t num_dsps);
    1. 创建一个不大于4K(0x0000 1000)的内存空间,起始地址为0xA000 2000。
  4. 函数int32_t sync_test_barr(void)
    1. 在此函数中主要调用
      mpm_sync_barr_wait(sync_test_barr_handle,DNUM+1);//DNUM+1?
    2. 函数int32_t mpm_sync_barr_wait(void *barr, int32_t user_id);
      1. 代码
        int32_t  mpm_sync_barr_wait(void *barr, int32_t user_id)// src/sync/mpm_sync_barr.c
        {
          mpm_sync_barr_t      *inst   = (mpm_sync_barr_t *)barr;
          mpm_sync_barr_user_t  *users  = &inst->users[0];
          int32_t          ret    = MPM_SYNC_BARR_ERROR_NONE;
          int32_t          i, tot;
        
          if ( inst == NULL )
            ret = MPM_SYNC_BARR_ERROR_HANDLE;
          else if ( (user_id < 0) || (user_id >= inst->num_users) )
            ret = MPM_SYNC_BARR_ERROR_USER_ID;
          else if ( (users[user_id].sw_barr != 0) || (users[user_id].sw_barr_passed != 0) )
            ret = MPM_SYNC_BARR_ERROR_CORRUPTION;
          else
          {
            users[user_id].sw_barr = 1;
        
            for (;;)
            {
              tot = 0;
        
              for ( i = 0; i < inst->num_users; i++)
                tot += users[i].sw_barr;
        
              if ( inst->num_users <= tot )
              {
                users[user_id].sw_barr_passed = 1;
        
                if ( user_id == 0 )
                {
                  for (;;)
                  {
                    tot = 0;
        
                    for ( i = 0; i < inst->num_users; i++)
                      tot += users[i].sw_barr_passed;
        
                    if ( inst->num_users <= tot )
                    {
                      memset ( users, 0, inst->num_users * sizeof(mpm_sync_barr_user_t));
                      break;
                    }
                  }
                }
                break;
              }
            }
          }
          return ( ret );
        }

      2. 看起来复杂,实际上理解,每当core访问到barrier时,相应的数据结构sw_barr赋值为1(初始值为0),表示“我来了”,此后直到所有的core都“来了”以后 ,(inst->num_users <= tot)即完成所有有请求的core等待同步,对每个core的sw_barr_passed变量赋值为1,表示“我走了”,在所有core"离开"之前,依旧需要循环等待,直到没有人再访问即当user_id==0(对应DNUM=-1)时,清空刚才的访问记录,并break。

你可能感兴趣的:(memory,barrier,openMPM)