Повышение производительности общей памяти - изоляция ядра Linux - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь оптимизировать производительность чтения и записи double в общую память.У меня одна программа пишет в общую память, а другая читает из нее.

Я использовал этот пост , чтобы помочь изолировать процессоры для этих двух программ для запуска, со следующей строкой в ​​моем etc/default/grub файле:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_idle.max_cstate=1 isolcpus=6,7"

Я использую taskset -c 6 writer и taskset -c 7 reader, чтобы настроить эти программы для запуска на этих процессорах.

Используя эту справочную страницу на sched_setscheduler , я настроил обе программы на самое высокое планированиеПриоритет с использованием следующего кода:

struct sched_param param;   
param.sched_priority = sched_get_priority_max(SCHED_FIFO);

if(sched_setscheduler(0, SCHED_FIFO, &param) == -1) 
{
     perror("sched_setscheduler failed");
     exit(-1);
}

Я определил структуру, которая будет использоваться в общей памяти, которая содержит необходимые инструменты синхронизации, а также структуру timepec и значение типа double для передачи между двумя программами, так какследует:

typedef struct
{
    // Synchronization objects
    pthread_mutex_t ipc_mutex;
    sem_t ipc_sem;
    // Shared data
    double value;
    volatile int read_cond;
    volatile int end_cond;
    double start_time;
    struct timespec ts;
} shared_data_t;

Инициализация общей памяти:

Писатель:

// ftok to generate unique key 
key_t key = ftok("shmfile",65); 

// shmget returns an identifier in shmid 
int shmid = shmget(key,1024,0666|IPC_CREAT); 
ftruncate(shmid, sizeof(shared_data_t));

// shmat to attach to shared memory 
shared_data_t* sdata = (shared_data_t*) shmat(shmid,(void*)0,0); 
sdata->value = 0;

Считыватель:

// ftok to generate unique key 
key_t key = ftok("shmfile",65); 

// shmget returns an identifier in shmid 
int shmid = shmget(key,1024,0666|IPC_CREAT); 
ftruncate(shmid, sizeof(shared_data_t));

// shmat to attach to shared memory 
shared_data_t* sdata = (shared_data_t*) shmat(shmid,(void*)0,0); 

Инициализация инструментов синхронизации в Writer

pthread_mutexattr_t mutex_attr;
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&sdata->ipc_mutex, &mutex_attr);
sem_init(&sdata->ipc_sem, 1, 0);

Код записи

for (int i = 0; i < 20000000; ++i)
    {
        pthread_mutex_lock(&sdata->ipc_mutex);
        sdata->value++;
        clock_gettime(CLOCK_MONOTONIC, &sdata->ts);
        sdata->start_time = (BILLION*sdata->ts.tv_sec) + sdata->ts.tv_nsec;
        sdata->read_cond = 1;
        pthread_mutex_unlock(&sdata->ipc_mutex);
        sem_wait(&sdata->ipc_sem);
    }
fprintf(stderr, "done writing\n" );

pthread_mutex_lock(&sdata->ipc_mutex);
sdata->end_cond = 1;
pthread_mutex_unlock(&sdata->ipc_mutex);

Считывание кода

double counter = 0;
double total_time = 0;
double max_time = 0;
double min_time = BILLION;
double max_thresh = 1000;
int above_max_counter = 0;
double last_val = 0;
while (1) {

        pthread_mutex_lock(&sdata->ipc_mutex);
        while (!sdata->read_cond && !sdata->end_cond) {
            pthread_mutex_unlock(&sdata->ipc_mutex);
            pthread_mutex_lock(&sdata->ipc_mutex);
        }

        clock_gettime(CLOCK_MONOTONIC, &sdata->ts);
        double time_to_read = (BILLION*sdata->ts.tv_sec) + sdata->ts.tv_nsec - sdata->start_time;

        if (sdata->end_cond) {
            break;
        }

        if (sdata->value != last_val + 1) {
            fprintf(stderr, "synchronization error: val: %g, last val: %g\n", sdata->value, last_val);
        }
        last_val = sdata->value;

        if (time_to_read > max_time) {
            max_time = time_to_read;
            printf("max time: %lf, counter: %ld\n", max_time, (long int) counter);
        }  
        if (time_to_read < min_time) min_time = time_to_read;

        if (time_to_read > max_thresh) above_max_counter++;
        total_time += time_to_read;
        counter++;

        sdata->read_cond = 0;
        sem_post(&sdata->ipc_sem);
        pthread_mutex_unlock(&sdata->ipc_mutex);

    }

fprintf(stderr, "avg time to read: %g\n", total_time / counter);
fprintf(stderr, "max time to read: %g\n", max_time);
fprintf(stderr, "min time to read: %g\n", min_time);
fprintf(stderr, "count above max threshhold of %g ns: %d\n", max_thresh, above_max_counter);

Очистка в Writer

//detach from shared memory 
shmdt(sdata); 

Очистка в считывателе

pthread_mutex_unlock(&sdata->ipc_mutex);
pthread_mutex_destroy(&sdata->ipc_mutex);

//detach from shared memory 
shmdt(sdata); 

// destroy the shared memory 
shmctl(shmid,IPC_RMID,NULL); 

Цель состоит в том, чтобы минимизировать количество времени, затрачиваемого на эти две операции.В идеале я хотел бы иметь возможность гарантировать, что время считывания с момента записи значения составляет менее 1 микросекунды.Тем не менее, вывод, который я получаю:

max time: 5852.000000, counter: 0
max time: 18769.000000, counter: 30839
max time: 27416.000000, counter: 66632
max time: 28668.000000, counter: 1820109
max time: 121362.000000, counter: 1853346
done writing
avg time to read: 277.959
max time to read: 121362
min time to read: 60
count above max threshhold of 1000 ns: 1871

, указывает, что в ряде случаев (~ 0,01% операций чтения) считывание превышает 1 единицу и может достигать 121us.

У меня такой вопрос:

Что может быть причиной этих пиков, поскольку я установил приоритет на самый высокий и изолировал ЦП, на котором работают эти программы?

Я узнал из этого поста , что не следует ожидать, что clock_gettime будет иметь наносекундную точность.Являются ли эти пики просто неточностями в clock_gettime?

Другой вариант, который я рассмотрел, заключается в том, что эти ядра (6 и 7) каким-то образом прерываются, несмотря на то, что они были установлены в качестве наивысшего приоритета.

Любая помощь будетс благодарностью.

EDIT

В комментариях ниже приведено содержимое моего /proc/interrupts файла:

           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       
   0:         20          0          0          0          0          0          0          0   IO-APIC    2-edge      timer
   1:          2          0          0          0          0          0          0          0   IO-APIC    1-edge      i8042
   8:          1          0          0          0          0          0          0          0   IO-APIC    8-edge      rtc0
   9:          0          0          0          0          0          0          0          0   IO-APIC    9-fasteoi   acpi
  12:          2          0          0          0          1          1          0          0   IO-APIC   12-edge      i8042
  16:          0          0          0          0          0          0          0          0   IO-APIC   16-fasteoi   i801_smbus, pcim_das1602_16
  19:          2          0          0          0          8         10          6          2   IO-APIC   19-fasteoi 
 120:          0          0          0          0          0          0          0          0   PCI-MSI 16384-edge      aerdrv
 121:         99        406          0          0         14       5960          6          0   PCI-MSI 327680-edge      xhci_hcd
 122:       8726        133         47         28       4126       3910      22638        795   PCI-MSI 376832-edge      ahci[0000:00:17.0]
 123:          2          0          0          0          2          0          3       3663   PCI-MSI 520192-edge      eno1
 124:       3411          0          2          1        176      24498         77         11   PCI-MSI 32768-edge      i915
 125:         45          0          0          0          3          6          0          0   PCI-MSI 360448-edge      mei_me
 126:        432          0          0          0        144        913         28          1   PCI-MSI 514048-edge      snd_hda_intel:card0
 NMI:          1          1          1          1          1          1          1          1   Non-maskable interrupts
 LOC:      12702      10338      10247      10515       9969      10386      16658      13568   Local timer interrupts
 SPU:          0          0          0          0          0          0          0          0   Spurious interrupts
 PMI:          1          1          1          1          1          1          1          1   Performance monitoring interrupts
 IWI:          0          0          0          0          0          0          0          0   IRQ work interrupts
 RTR:          7          0          0          0          0          0          0          0   APIC ICR read retries
 RES:       4060       2253       1026        708        595        846        887        751   Rescheduling interrupts
 CAL:      11906      10423      11418       9894      14562      11000      21479      11223   Function call interrupts
 TLB:      10620       8996      10060       8674      13172       9622      20121       9838   TLB shootdowns
 TRM:          0          0          0          0          0          0          0          0   Thermal event interrupts
 THR:          0          0          0          0          0          0          0          0   Threshold APIC interrupts
 DFR:          0          0          0          0          0          0          0          0   Deferred Error APIC interrupts
 MCE:          0          0          0          0          0          0          0          0   Machine check exceptions
 MCP:          2          2          2          2          2          2          2          2   Machine check polls
 ERR:          0
 MIS:          0
 PIN:          0          0          0          0          0          0          0          0   Posted-interrupt notification event
 PIW:          0          0          0          0          0          0          0          0   Posted-interrupt wakeup event

Имеюпопытался изменить сходство smp для прерываний 122 и 123 на ядра 0 и 1, для этого поста , который, похоже, ничего не делает, так как, когда я перезагружаю свой компьютер, эти сходства все еще устанавливаются на ядра 6 и 7,

Даже без сброса и простого повторного запуска моих программ я не вижу изменений в количестве прерываний, обслуживаемых этими ядрами ЦП.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...