Estoy probando el rendimiento de una tarjeta Samsung 950 Pro SSD que utiliza el protocolo NVMe. Mi método de prueba actual es montar un sistema de archivos en una partición y escribir un archivo de tamaño X bytes en el sistema de archivos. Al registrar el tiempo que lleva hacerlo, se pueden calcular los bytes/segundo.
En mi prueba, tengo un bucle while que escribirá hasta X bytes en tamaños de bloque variables, un bloque a la vez, especificado por un bucle for de nivel superior. Además de esto, también tengo otro bucle que ejecutará N de estas aplicaciones en paralelo, cada aplicación escribiendo en una partición diferente del SSD.
Actualmente, veo velocidades ligeramente más rápidas que la velocidad de transferencia máxima teórica especificada en la hoja de datos del Samsung 950 Pro tanto para lectura como para escritura. Samsung especificó que la velocidad máxima de escritura secuencial para el 950 Pro es de 1,5 GB/s y la velocidad máxima de lectura secuencial es de 2,5 GB/s.
Aquí está la función principal del script bash que recorre la cantidad de aplicaciones para ejecutar y los tamaños de bloque:
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
Aquí está la sección de escritura de run_perf_test. También hay una sección de lectura después de esta parte, que comprende la prueba de velocidad de rendimiento de escritura. Entre las pruebas, desmonto todas las particiones del SSD y las vuelvo a montar para permitir que se completen todas las transacciones NVMe y evitar que el almacenamiento en caché escriba operaciones para influir en la medición del rendimiento de la operación de lectura.
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 es una aplicación C++ que, basándose en el primer argumento, "-r" o "-w", el segundo argumento, el tamaño del bloque y el tercer argumento, el nombre del archivo, que es un archivo en la partición SSD, creará una cadena. e intente abrir el archivo en la partición SSD y escribirle la cadena. Aquí está la implementación de la función de escritura, que se llama cuando se proporciona "-w" como primer argumento.
/*! \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;
}
Los datos que estoy recibiendo se ven así
Los números están cerca del rendimiento máximo teórico del Samsung 950 Pro, pero algunos son demasiado altos y esto me preocupa. ¿Por qué podría obtener cifras superiores al rendimiento máximo teórico del Samsung 950 Pro?