NMVe SSD Fedora 처리량 테스트가 너무 높습니다.

NMVe SSD Fedora 처리량 테스트가 너무 높습니다.

NVMe 프로토콜을 사용하여 Samsung 950 Pro SSD 카드의 처리량을 테스트하고 있습니다. 현재 테스트 방법은 파티션에 파일 시스템을 마운트하고 X바이트 크기의 파일을 파일 시스템에 쓰는 것입니다. 이 작업을 수행하는 데 걸리는 시간을 기록하여 바이트/초를 계산할 수 있습니다.

내 테스트에는 더 높은 수준의 for 루프에 지정된 대로 한 번에 한 블록씩 가변 블록 크기로 X 바이트를 쓰는 while 루프가 있습니다. 이 외에도 N개의 애플리케이션을 병렬로 실행하고 각각 SSD의 다른 파티션에 쓰는 또 다른 루프가 있습니다.

현재 Samsung 950 Pro 데이터시트에 지정된 이론적 최대 전송 속도보다 약간 빠른 읽기 및 쓰기 속도가 보입니다. Samsung은 950 Pro의 최대 순차 쓰기 속도를 1.5GB/s, 최대 순차 읽기 속도를 2.5GB/s로 지정합니다.

https://www.samsung.com/us/computing/memory-storage/solid-state-drives/ssd-950-pro-nvme-512gb-mz-v5p512bw/#specs

실행할 애플리케이션 수와 청크 크기를 반복하는 bash 스크립트의 주요 기능은 다음과 같습니다.

appInstances=1
while [ $appInstances -le 4 ]
do
    for blocksize in 4096 32768 131072 524288 1048576 67108864 268435456 1073741824
    do
       # Run the test
       datetime
       echo "[$datetime_v]: Test blocksize: $blocksize appInstances: $appInstances"
       run_single_perf_test $blocksize

    done

    appInstances=`expr $appInstances \* 2`

done
exit 0

run_perf_test의 쓰기 부분입니다. 이 섹션 뒤에는 쓰기 처리량 속도 테스트가 포함된 읽기 섹션이 있습니다. 테스트 사이에 SSD의 모든 파티션을 마운트 해제했다가 다시 마운트하여 모든 NVMe 트랜잭션이 완료되도록 하고 쓰기 작업 캐싱이 읽기 작업의 처리량 측정에 영향을 미치지 않도록 했습니다.

instCnt=1
childpids=""
while [ $instCnt -le $appInstances ]
do
fsrw -w $blocksize /fsmnt/fs${instCnt}/usernumber1/j.j &

# Save the process ID
childpids="$childpids $!"

# Increment the instace count.
instCnt=`expr $instCnt + 1`
done

fsrw는 첫 번째 인수 "-r" 또는 "-w", 두 번째 인수(블록 크기) 및 세 번째 인수(SSD 파티션의 파일 이름)를 기반으로 문자열을 작성하고 SSD에서 파일 열기를 시도하는 C++ 애플리케이션입니다. 파티션을 나누고 문자열을 씁니다. 이는 첫 번째 인수로 "-w"가 제공될 때 호출되는 쓰기 함수의 구현입니다.

/*! \fn perform_writeop()
 *  \brief The function returns true when the write operation completes successfully. 
 *
 *  The function will run until the read is complete or a 35 second timeout is reached.
 *  It will record the time before the write begins, then also record the time afterward.
 *  If the timeout is reached this should be about 35 seconds
 */
bool perform_writeop ()
{
    // File descriptor.
    int32_t fd = -1;

    // Function status.
    bool status = false;

    // Zero writes
    int zero_writes = 0;

    // Buffer fill index.
    int32_t bfidx = 0;

    // Character value.
    int8_t cv = 33;

    // Fill the buffer with printable characters.
    for (; bfidx < blocksize; bfidx++, cv++)
    {
        // Verify the character value is in range.
        if (cv >= 127)
        {
            cv = 33;
        }
        else
        {
            // Add to the buffer.
            buf[bfidx] = cv;
        }
    }

    // Open the file.
    fd = open (fname.c_str (), O_WRONLY | O_CREAT, 0660);

    // Verify the file has been opened.
    if (fd == -1)
    {
        cout << get_datetime_string() << "Write open of " << fname 
        << " failed.  Errno: " << errno << endl;
    }
    else
    {
        // Total bytes written.
        uint64_t written = 0;

        // Notify the start of the test.
        cout << get_datetime_string() << "Write test started" << endl;

        // Elapsed time.
        struct timeval tv = { 0 };
        get_elapsed_time (&tv);
        struct timeval write_tv = tv;

        // Run until it is time for the test to stop.
        while (written < READ_LIMIT && zero_writes < 10)
        {
            ssize_t writesize = write (fd, &buf[0], blocksize);
            if (writesize == -1)
            {
                cout << get_datetime_string << "Write failure.  Errno: " << errno << endl;
                zero_writes = 10;
            }
            else if (0 == writesize)
            {
                cout << get_datetime_string() << "Zero bytes written" << endl;
                zero_writes++;
            }
            else
            {
                written += writesize;
            }
        }

    string flush_command = "nvme flush /dev/nvme0n1p";
    flush_command += fname[9];
    system(flush_command.c_str());


    // Get the elapsed time.
    get_elapsed_time (&write_tv);

    // Report the number of bytes written.
    cout << get_datetime_string() << "Write " << written << " bytes in "
     << write_tv.tv_sec << "." << write_tv.tv_usec
     << " seconds" << endl;

    // Close the file.
    close (fd);

    // Get the elapsed time.
    get_elapsed_time (&tv);

    // Report the number of bytes read.
    cout << get_datetime_string() << "Write closed.  " << written 
    << " Bytes written in " << tv.tv_sec << "." << tv.tv_usec 
    << " seconds" << endl;

    // Report the number of bytes per second.
    cout << get_datetime_string() << "Bytes per second " 
    << bytes_per_second (&tv, written) << endl;

    // Report the cache flush time.
    struct timeval flush_tv = { 0 };
    timersub (&tv, &write_tv, &flush_tv);
    cout << get_datetime_string() << "System cache flush completed in " 
    << flush_tv.tv_sec << "." << flush_tv.tv_usec << "seconds" << endl;

    // Set the function return status when all write operations have
    // been successful.
    if (zero_writes < 10)
    {
      status = true;
    }
  }
  return status;
}

내가 얻는 데이터는 다음과 같습니다 여기에 이미지 설명을 입력하세요.

이 수치는 Samsung 950 Pro의 이론상 최대 처리량에 가깝지만 일부 수치는 너무 높아서 신경이 쓰입니다. 내가 얻는 수치가 Samsung 950 Pro의 이론적 최대 처리량보다 높은 이유는 무엇입니까?

관련 정보