Linux 페이지 캐시 성능 및 memcpy

Linux 페이지 캐시 성능 및 memcpy

저는 프로세스를 제한하거나 데이터를 디스크에 동기화하지 않고 페이지 캐시에 데이터를 쓰는 Linux의 쓰기 성능을 벤치마킹하고 있습니다. 제가 하고 있는 간단한 실험은 다음과 같습니다.

long size = 1024;
int fd = open ("file", O_CREAT | O_RDWR | O_TRUNC, ...);
char *buffer = (char *) malloc (size)
**start_time = time.now ();**
write (fd, buffer, size);
**end_time = time.now ();**
close (fd);
printf ("write duration %d\n", end_time - start_time);

여기서는 데이터가 운영 체제의 페이지 캐시에만 복사되고 디스크에는 아무것도 동기화되지 않으므로 메모리 대역폭을 효과적으로 관찰할 수 있기를 바랍니다. 또한 더티 비율이 background_dirty_ratio보다 훨씬 낮기 때문에 운영 체제는 백그라운드 플러시 또는 제한 프로세스를 시작하지 않았습니다. 그러나 메모리 대역폭(동일 크기에 대한 memcpy 비용)과 비교하면 memcpy보다 훨씬 비쌉니다.

char *buffer1 = (char *) malloc (size)
char *buffer2 = (char *) malloc (size)
**start_time = time.now ();**
memcpy (buffer1, buffer2, size);
**end_time = time.now ();**
printf ("memcpy duration %d\n", end_time - start_time);

예를 들어 내 시스템(Linux 커널 버전 4.2, CentOS)에서 memcpy 대역폭은 거의60GB/초, 쓰기 대역폭은 거의2GB/초. 내가 이해한 바로는 쓰기 시스템 호출이 호출되면 페이지 캐시(메모리 내)에서 데이터를 복사하고 복사가 완료되자마자 반환됩니다. 그래서 메모리 대역폭에 가까운 대역폭을 볼 것으로 예상됩니다. 또한 시스템 호출 비용을 줄이기 위해 더 큰 데이터(OS가 프로세스 조절을 시작하기 전)를 사용하여 동일한 실험을 테스트했습니다. 그러나 나는 여전히 거의 동일한 결과를 봅니다. 페이지 캐시에 쓰기를 수행할 때 메모리 대역폭을 관찰하지 못하는 이유를 아는 사람이 있습니까?

답변1

여기서 주요 요소는 memcpyC 라이브러리에 의해 처리되거나 C 컴파일러에 의해 직접 처리되지 write않고 커널에 의해 처리되는 시스템 호출입니다.

따라서 memcpy실행이 진행 중이며 함수 호출의 (작은) 오버헤드가 없을 수도 있습니다. write반면에 시스템 호출의 모든 오버헤드가 있습니다. 특히 테스트에서는 쓰기 크기가 작기 때문에 복사 자체 비용이 시스템 호출 비용에 비해 작아질 수 있습니다. 대규모 테스트에서도 시스템 호출 비용이 여전히 주요 요인이 될 수 있습니다.

시스템 호출의 무게를 줄이려면 더 큰 크기와 비교하고, 필요한 경우 더티 속도 구성을 변경하거나, tmpfs디스크 쓰기 비용을 피하기 위해 a를 작성하세요. 당신은 또한 원할 수도 있습니다시스템 호출 비용을 증가시키는 KPTI 및 기타 완화 기능을 비활성화합니다., 그리고 io_uring을 살펴보세요.

처리와 관련된 작업에 대한 더 나은 아이디어를 얻으려면 write다음을 수행하십시오.__x64_sys_writex86-64에서 해당 시스템 호출을 추적합니다.;콜 체인과 소요 시간이 표시됩니다.예를 들어

  9)               |  __x64_sys_write() {
  9)               |    ksys_write() {
  9)               |      __fdget_pos() {
  9)               |        __fget_light() {
  9)   0.465 us    |          __fget_files();
  9)   0.943 us    |        }
  9)   1.155 us    |      }
  9)               |      vfs_write() {
  9)               |        rw_verify_area() {
  9)               |          security_file_permission() {
  9)               |            selinux_file_permission() {
  9)               |              __inode_security_revalidate() {
  9)               |                _cond_resched() {
  9)   0.034 us    |                  rcu_all_qs();
  9)   0.241 us    |                }
  9)   0.649 us    |              }
  9)               |              file_has_perm() {
  9)   0.034 us    |                bpf_fd_pass();
  9)               |                inode_has_perm() {
  9)   0.133 us    |                  avc_has_perm();
  9)   0.376 us    |                }
  9)   0.808 us    |              }
  9)   2.126 us    |            }
  9)   0.032 us    |            bpf_lsm_file_permission();
  9)   2.616 us    |          }
  9)   2.815 us    |        }
  9)               |        __vfs_write() {
  9)               |          new_sync_write() {
  9)               |            pipe_write() {
  9)               |              mutex_lock() {
  9)               |                _cond_resched() {
  9)   0.034 us    |                  rcu_all_qs();
  9)   0.236 us    |                }
  9)   0.566 us    |              }
  9)               |              _cond_resched() {
  9)   0.036 us    |                rcu_all_qs();
  9)   0.232 us    |              }
  9)   0.036 us    |              mutex_unlock();
  9)               |              __wake_up_sync_key() {
  9)               |                __wake_up_common_lock() {
  9)   0.036 us    |                  _raw_spin_lock_irqsave();
  9)               |                  __wake_up_common() {
  9)               |                    pollwake() {
  9)               |                      default_wake_function() {
  9)               |                        try_to_wake_up() {
  9)   0.178 us    |                          _raw_spin_lock_irqsave();
  9)               |                          select_task_rq_fair() {
  9)   0.033 us    |                            available_idle_cpu();
  9)   0.032 us    |                            available_idle_cpu();
  9)   0.040 us    |                            cpus_share_cache();
  9)   0.058 us    |                            available_idle_cpu();
  9)   1.061 us    |                          }
  9)   0.036 us    |                          ttwu_queue_wakelist();
  9)   0.036 us    |                          _raw_spin_lock();
  9)   0.079 us    |                          update_rq_clock();
  9)               |                          ttwu_do_activate() {
  9)               |                            enqueue_task_fair() {
  9)               |                              enqueue_entity() {
  9)   0.040 us    |                                update_curr();
  9)   0.088 us    |                                __update_load_avg_se();
  9)   0.070 us    |                                __update_load_avg_cfs_rq();
  9)   0.032 us    |                                update_cfs_group();
  9)   0.055 us    |                                __enqueue_entity();
  9)   1.347 us    |                              }
  9)               |                              enqueue_entity() {
  9)   0.038 us    |                                update_curr();
  9)   0.077 us    |                                __update_load_avg_se();
  9)   0.050 us    |                                __update_load_avg_cfs_rq();
  9)               |                                update_cfs_group() {
  9)   0.047 us    |                                  reweight_entity();
  9)   0.289 us    |                                }
  9)   0.035 us    |                                __enqueue_entity();
  9)   1.469 us    |                              }
  9)   0.033 us    |                              hrtick_update();
  9)   3.546 us    |                            }
  9)               |                            ttwu_do_wakeup() {
  9)               |                              check_preempt_curr() {
  9)   0.046 us    |                                resched_curr();
  9)   0.279 us    |                              }
  9)   0.671 us    |                            }
  9)   4.653 us    |                          }
  9)   0.038 us    |                          _raw_spin_unlock_irqrestore();
  9)   7.458 us    |                        }
  9)   7.652 us    |                      }
  9)   7.924 us    |                    }
  9)   8.865 us    |                  }
  9)   0.045 us    |                  _raw_spin_unlock_irqrestore();
  9)   9.501 us    |                }
  9)   9.703 us    |              }
  9)   0.033 us    |              kill_fasync();
  9)   0.055 us    |              __sb_start_write();
  9)               |              file_update_time() {
  9)               |                current_time() {
  9)   0.037 us    |                  ktime_get_coarse_real_ts64();
  9)   0.039 us    |                  timestamp_truncate();
  9)   0.454 us    |                }
  9)               |                __mnt_want_write_file() {
  9)   0.057 us    |                  __mnt_want_write();
  9)   0.289 us    |                }
  9)               |                generic_update_time() {
  9)   0.089 us    |                  __mark_inode_dirty();
  9)   0.321 us    |                }
  9)   0.039 us    |                __mnt_drop_write_file();
  9)   1.904 us    |              }
  9)   0.037 us    |              __sb_end_write();
  9) + 14.315 us   |            }
  9) + 14.620 us   |          }
  9) + 14.840 us   |        }
  9)   0.166 us    |        __fsnotify_parent();
  9)   0.095 us    |        fsnotify();
  9) + 18.702 us   |      }
  9)               |      fput() {
  9)   0.035 us    |        fput_many();
  9)   0.238 us    |      }
  9) + 20.668 us   |    }
  9) + 20.907 us   |  }

이는 상당히 극단적인 예이지만 시스템 호출이 결국 메모리 복사 이상의 작업을 수행할 수 있음을 보여줍니다.

답변2

통화를 적절하게 추가하면동기화(2)또는동기화(2)코드에서 Linux 커널이 일부 데이터를 디스크로 보낼 것으로 예상해야 합니다.

하지만 2022년에는 디스크가 대개 SSD이고, 디스크 자체에도 일부 버퍼가 있게 됩니다.

당신은 또한 볼 수 있습니다시간(7),표준편차(4), 사용시계 가져오기 시간(2), 그리고 아마도 더 있을 수도 있습니다(모르겠어요)ioctl(2)또는FCNTL(2)또는io_submit(2)하드 드라이브가 물리적 수준에서 데이터를 쓰도록 강제합니다...

어쩌면 커널 모듈을 작성해야 할 수도 있습니다.

관련 정보