Я работаю над встроенным Linux (ядро-5.10.24) и теперь запускаю программу на C для стресс-тестирования копирования файлов. Код использует stdio
для чтения и записи файла следующим образом:
#include <stdio.h>
#include <stdlib.h> // For exit()
#include <unistd.h>
#include <string.h>
#ifndef BUF_SIZE /* Allow "cc -D" to override definition */
#define BUF_SIZE 1024
#endif
static unsigned char buf[BUF_SIZE];
static char *infname = "/tmp/src_file.bin";
static char *ofname = "/tmp/dst_file.bin";
static int create_dest_file(const char *fname)
{
FILE *fp = fopen(fname, "w");
if (fp == NULL) {
printf("Failed to create/truncate %s\n", fname);
return 1;
}
fclose(fp);
return 0;
}
static int copy_file(const char *src, const char *dest)
{
FILE *fp, *fp2;
int rlen = 0, wlen = 0, rc = 0;
// Open one file for reading
fp = fopen(src, "r");
if (fp == NULL)
{
printf("Cannot open file %s\n", src);
return 1;
}
fp2 = fopen(dest, "ab");
if (fp2 == NULL) {
fclose(fp);
return 1;
}
while (1) {
rlen = fread(buf, 1, sizeof(buf), fp);
if (rlen > 0) {
wlen = fwrite(buf, 1, rlen, fp2);
if (wlen != rlen) {
printf("Wrote len: %d, read len: %d\n", wlen, rlen);
rc = 1;
break;
}
} else {
break;
}
}
fclose(fp);
fclose(fp2);
return rc;
}
int main(int argc, char **argv)
{
int i = 0, rc = 0;
int us = 500000;
if (argc != 4) {
printf("Usage: %s srcfile dstfile delay_in_us\n", argv[0]);
return 1;
}
infname = argv[1];
ofname = argv[2];
us = atoi(argv[3]);
printf("Copying %s to %s\n", infname, ofname);
for (i = 0; i < 1000; i++) {
create_dest_file(ofname);
rc = copy_file(infname, ofname);
printf("XXXXXXXXXXX %d, rc: %d\n", i, rc);
usleep(us);
}
return 0;
}
После компиляции и запуска с помощью ./filecopy /root/16MB_src.bin /root/dest.bin 250000
я получал несколько разных типов ошибок, таких как Segmentation fault
, Bus error
, Illegal instruction
и так далее.
Я установил GDB для запуска filecopy
и получил следующую ошибку.
XXXXXXXXXXX 45, rc: 0
XXXXXXXXXXX 46, rc: 0
Fatal error: glibc detected an invalid stdio handle
Program received signal SIGABRT, Aborted.
0x77cdfd44 in ?? () from /lib/libc.so.6
(gdb) bt
#0 0x77cdfd44 in ?? () from /lib/libc.so.6
#1 0x77c964ac in raise () from /lib/libc.so.6
#2 0x77c97ae4 in abort () from /lib/libc.so.6
warning: GDB can't find the start of the function at 0x77cd0c97.
#3 0x77cd0c98 in ?? () from /lib/libc.so.6
(gdb)
Я проверил код и попросил других коллег просмотреть код, ошибок не обнаружено :-(.
Судя по типам ошибок, код вызывал одни и те же случайные сбои, но я не могу найти основную причину.
Система имеет 64 МБ ОЗУ, размер исходного файла составляет около 18 МБ, библиотека libc — GLIBC2.38.
Многие тесты показали, что если размер исходного файла составляет около 1 МБ, программа работает хорошо, ошибок не возникает.
Если исходный файл около 8 МБ и 18 МБ, программа выдаёт ошибки.
Если файл (18 МБ) читается из NAND и записывается в ОЗУ, значит, все прошло хорошо.
Если файл (18 МБ) читается из ОЗУ и записывается в NAND, возникает ошибка.
Результат free -k
показал
# free -k
total used free shared buff/cache available
Mem: 54580 13228 9404 344 31948 38260
Swap: 0 0 0
# free -k
total used free shared buff/cache available
Mem: 54580 13252 17480 344 23848 38240
Swap: 0 0 0
# free -k
total used free shared buff/cache available
Mem: 54580 13260 11936 344 29384 38232
Swap: 0 0 0
# free -k
total used free shared buff/cache available
Mem: 54580 13252 6656 344 34672 38240
Swap: 0 0 0
# free -k
total used free shared buff/cache available
Mem: 54580 13244 19304 344 22032 38224
Память НЕ израсходована.
🤔 А знаете ли вы, что...
C оставляет множество возможностей для оптимизации кода и достижения высокой производительности приложений.
Кажется, с вашей программой все в порядке, ваша проблема, скорее всего, кроется в другом.
Я получал несколько различных типов ошибок, таких как ошибка сегментации, ошибка шины, недопустимая инструкция и так далее.
Все это может быть результатом плохой памяти (чтение значений, отличных от записанных ранее).
Я предлагаю запустить программу проверки памяти, чтобы подтвердить или исключить эту возможность.
Вы также можете запустить другие известные стабильные приложения, интенсивно использующие память (например, сам gcc
) — если вы также видите сбои в них, весьма вероятной основной причиной является «плохая память».