【问题标题】:System V Semaphore vs Posix Semaphore performance on ARM8ARM8 上的 System V Semaphore 与 Posix Semaphore 性能
【发布时间】:2021-12-05 12:59:58
【问题描述】:

我正在比较具有 Linux ubuntu 4.15.0-112 的 ARM8 服务器上的许多进程的性能,每个进程都试图获取信号量(信号量始终处于争用状态)

首先我使用了一个命名的 posix 信号量,然后使用了一个 system v 信号量,其中信号量集有 1 个信号量。

使用 system v 信号量时,性能降低了 8%。我知道当信号量没有争用时它的性能会更差,但我不明白有时性能会受到什么影响。 在 intel 上运行相同的程序时,我看不出性能有任何差异,但我相信在 intel 上运行时还有其他的瓶颈。

我想使用 System V Semaphore 有两个原因,释放信号量以防其中一个进程崩溃,并且可以按任何值而不是 +-1 递增/递减

这是我为 system v semaphore 编写的代码(仅从 1 个进程调用初始化,并且在等待和发布中没有撤消标志的情况下,我得到了相同的性能影响)

void init_semaphore(bool initialize, int initCount, int& semId)
{
key_t key;
char* file_path = "/tmp/semv";
char proj_id ='p';
if (initialize)
{
  
    key = ftok(file_path, proj_id);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }
    int flags = IPC_CREAT | 0666;

    semId = semget(key, 1, flags);
    if (semId == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }

    i = semctl(semId, 0, SETVAL, initCount);
    if (i == -1) {
        perror("semctl");
        exit(EXIT_FAILURE);
    }
    i = semctl(semId, 0, GETVAL);
    printf("current value of %d is %d\n", semId, i);

}
else
{
    key = ftok(file_path, proj_id);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }
    semId = semget(key, 1, 0);
    if (semId == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }
}
}

void release_semaphore(int semId)
{
int i = semctl(semId, 0, IPC_RMID);
if (i == -1) {
    perror("semctl: semctl failed");
    exit(1);
}
}

void post(int semId)
{
sembuf sops_post[1];
sops_post[0].sem_num = 0;        
sops_post[0].sem_op = 1;
sops_post[0].sem_flg = SEM_UNDO;
semop(semId, sops_post, 1);
}


void wait(int semId)
{
sembuf sops_wait[1];
sops_wait[0].sem_num = 0;        
sops_wait[0].sem_op = -1;
sops_wait[0].sem_flg = SEM_UNDO;
semop(semId, sops_wait, 1);
}

【问题讨论】:

    标签: performance semaphore arm64


    【解决方案1】:

    释义:为什么 ARM 上的 SystemV 信号量争用比 Intel 更严重?

    TL;DR - System V 使用 Linux RCU。 RCU 是一种无锁算法,它将依赖于处理器内存模型。对于 Intel CPU,TSO 内存模型比ARM memory model 宽容得多。


    在 ARM Linux 上,semopimplemented as a syscall。系统调用有很大的开销。对于 Posix,它是通过在 vector/kuser 表中调用__kuser_cmpxchg 来实现的。这就像concept of a vDSO;实际上,它是 ARM64 上的 vDSO。在ARM32上是用向量表映射的。

    semop 的代码位于sem.c

    看看代码的复杂度!一个涉及系统调用,它是模式切换,需要完整的用户状态存储和可能的上下文切换。对于争用,posix 信号量将在循环中旋转,

        .inst   0xe1923f9f              // 1:   ldrex           r3, [r2]
        .inst   0xe0533000              //      subs            r3, r3, r0
        .inst   0x01823e91              //      stlexeq         r3, r1, [r2]
        .inst   0x03330001              //      teqeq           r3, #1
        .inst   0x0afffffa              //      beq             1b
    

    它后面有一个屏障,以确保其他核心的可观察性。 semop 的整个机制在 Linux VFS 和 RCU 上分层。对于系统全局信号量,人们可能希望使用 System V 是有道理的。但是,为了提高效率,Posix 信号量对于单进程多线程逻辑要好得多。

    当您检查它们时,这些机制是日以继夜的。 Posix 将保持在用户模式下,仅执行近 100 条指令,并保持在用户空间中的紧密循环(如自旋锁)内。 System V 正在使用 1000 条指令进行系统调用和模式更改。

    有关 Posix 信号量的更多信息,请参阅我的问题 my answer(接近尾声)。如果您绘制时序的直方图,我认为 System V 将显示比 Posix 时序更糟糕的情况。差 8% 可能是典型/平均差异。 sem.c 中的源将更糟糕的情况描述为 O(n^2),我假设“n”是竞争储物柜的数量。对于 Posix,某些线程将始终拥有锁,然后首先成功的 strex 将拥有更新;它是 O(1)。


    使用 system v 信号量时,性能降低了 8%。我知道 当信号量上没有争用 ARM 时性能更差, 但我不明白当有性能受到影响时。跑步时 在英特尔上也一样,我看不出性能有任何差异,但我 相信其他东西是在英特尔上运行时的瓶颈。

    英特尔的内存模型是 TSO,因此 RCU 代码在争用情况下可能更有效。对于 ARM,内存模型更像是 Power。它将需要许多smp_wb()smp_rb(),而英特尔可能不需要这些。这些指令将减慢所有内核,因为它们是全局的并且需要同步所有内核管道。

    正如 Wikipedia 的 memory model 所示,其他 CPU 会表现出更大的性能下降,例如 Alpha。

    【讨论】:

      猜你喜欢
      • 2019-11-06
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-02
      • 1970-01-01
      • 2017-07-20
      • 1970-01-01
      相关资源
      最近更新 更多