Hi,

Problem Statement
Our application uses System V semaphore extensively. We are facing performance 
issue with it.

Problem Description
We have created a sample code (attached with name shm_sem.cpp) which uses 
System V shared memory and semaphore. This code takes semaphore lock, updates 
the shared memory and unlock semaphore. It is done in a loop for 50k times. It 
takes around 21 seconds to complete. We have compiled and executed the same 
code on Linux which completes instantly. Following is the outcome of run from 
Cygwin and REHL 7.9 Linux VM:

Cygwin:
uname -a
CYGWIN_NT-10.0-17763 Win19Build01 3.5.3-1.x86_64 2024-04-03 17:25 UTC x86_64 
Cygwin

Compiled with : g++ -o shm_sem shm_sem.cpp

shm_sem.exe

2024-09-04 01:23:44.505687 => Starting...
2024-09-04 01:24:05.500330 => Finished...
2024-09-04 01:24:05.500989 => Shared memory and semaphore cleaned up.

RHEL Linux:
uname -a
Linux Linux6BuildDev03 3.10.0-1160.59.1.el7.x86_64 #1 SMP Wed Feb 16 12:17:35 
UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Compiled with : g++ -o shm_sem shm_sem.cpp

./shm_sem

2024-09-04 08:22:16.302955 => Starting...
2024-09-04 08:22:16.385529 => Finished...
2024-09-04 08:22:16.385631 => Shared memory and semaphore cleaned up.

Is this expected behavior or there are any configuration or any changes you can 
suggest which might improve its performance will be very helpful.

Attachments:

  1.  Sample code : shm_sem.cpp

  1.  Cygserver config file: cygserver.conf

  1.  Cygcheck output (cygcheck -s -v -r > cygcheck.out): cygcheck.out

Thanks,
Abinash Mohanty
/* System V Semaphore */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
 
#define SHM_SIZE 1024  // Shared memory size
#define SEM_KEY 0x1234 // Semaphore key
#define SHM_KEY 0x5678 // Shared memory key
 
// Union required for semctl
union semun {
    int val;               // value for SETVAL
    struct semid_ds *buf;  // buffer for IPC_STAT, IPC_SET
    unsigned short *array; // array for GETALL, SETALL
};
 
void error(const char *msg) {
    perror(msg);
    exit(1);
}

void log_write(const char *format, ...) {
    va_list args;
    int count;
    char buf[1024];
    struct timeval tval;
    struct tm lt;
    char time_stamp[100];

    gettimeofday(&tval, NULL);
    localtime_r(&tval.tv_sec, &lt);

    sprintf(time_stamp, "\n%04d-%02d-%02d %02d:%02d:%02d.%06d",
            lt.tm_year+1900, lt.tm_mon+1, lt.tm_mday,
            lt.tm_hour, lt.tm_min, lt.tm_sec, (int)tval.tv_usec);

    va_start( args, format );
    count = vsprintf( buf, format, args);
    va_end( args );

    if ( buf[strlen(buf)-1] == '\n' )
        buf[strlen(buf)-1] = 0;

    printf( "%s => %s", time_stamp, buf);
}

int sem_block(int sem_id,int sem_num)
{
        struct sembuf sops;
        sops.sem_num = sem_num;
        sops.sem_op = -1;
        sops.sem_flg = SEM_UNDO;

        if (semop(sem_id, (struct sembuf *)&sops,1) == -1) {
            if (errno != EINTR)
                error ("sem_block: semop error\n");
            return(-1);
        }
        return(0);
}

int sem_clear(int sem_id,int sem_num)
{
        struct sembuf sops;
        sops.sem_num = sem_num;
        sops.sem_op = 1;
        sops.sem_flg = SEM_UNDO;

        if (semop(sem_id, (struct sembuf *)&sops,1) == -1) {
            if (errno != EINTR)
                error ("sem_clear: semop error\n");
            return(-1);
        }
    return(0);
}

void sem_enter (int sem_id, int sem_num)
{
    int rv;

    do {
        rv = sem_block(sem_id,sem_num);
    } while (rv == -1 && errno == EINTR);

    if (rv == -1)
        error ("que_enter: sem_block error\n");
}

void sem_leave (int sem_id, int sem_num)
{
    int rv;

    do {
        rv = sem_clear(sem_id,sem_num);
    } while (rv == -1 && errno == EINTR);

    if (rv == -1)
        error ("que_leave: sem_clear error\n");
}
 
int main() {
    int shm_id, sem_id;
    void *shm_ptr;
    int nsems = 1;
 
    // Create shared memory
    shm_id = shmget(SHM_KEY, SHM_SIZE, 0644 | IPC_CREAT | IPC_EXCL);
    if (shm_id == -1)
        error("shmget");
 
    // Attach shared memory
    shm_ptr = shmat(shm_id, NULL, 0);
    if (shm_ptr == (void *)-1)
        error("shmat");
 
    // Create semaphore
    sem_id = semget(SEM_KEY, nsems, 0666 | IPC_CREAT|IPC_EXCL);
    if (sem_id == -1)
        error("semget");
 
    // Initialize semaphore to 1 (unlocked state)
    union semun sem_union;
    sem_union.val = 1;

    for ( int i = 0; i < nsems; i++ ) {
        if (semctl(sem_id, i, SETVAL, sem_union) == -1)
            error("semctl SETVAL");
    }

    log_write("Starting...\n");

    int num_out = 0;

    for (int num_in = 1; num_in <= 50000; num_in++ ) {
        // Semaphore lock
        sem_enter(sem_id, 0);

        // Write to shared memory
        memcpy(shm_ptr, &num_in, sizeof(int));

        // Semaphore unlock
        sem_leave(sem_id, 0);
    }

    log_write("Finished...\n");

    // Cleanup

    // Detach shared memory
    if (shmdt(shm_ptr) == -1)
        error("shmdt");

    // Remove shared memory
    if (shmctl(shm_id, IPC_RMID, NULL) == -1)
        error("shmctl");

    // Remove semaphore
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        error("semctl IPC_RMID");

    log_write("Shared memory and semaphore cleaned up.\n");
 
    return 0;
}

Attachment: cygcheck.out
Description: cygcheck.out

Attachment: cygserver.conf
Description: cygserver.conf

Reply via email to