Чтобы опираться на то, что уже указали другие пользователи, я попытаюсь ответить на оба вопроса ОП.
Первый вопрос ОП:
Я хотел бы знать, сколько стека и кучи в байтах требуется для суммы функций на платформе X86 Linux? Как это узнать?
Мы можем разбить этот первый вопрос на 2 части. Один касается размера стека, а другой - размера кучи.
Размер стека:
Чтобы узнать, сколько стека использует ваша функция, вы можете использовать одну из диагностических прагм GCC, то есть прагму -Wframe-larger-than=<X>
. Вот пример того, как его использовать. Сначала мы добавляем прагму в код и сохраняем файл.
main.cpp
#include <stdio.h>
#pragma GCC diagnostic error "-Wframe-larger-than=1"
int sum(int b[], int c) {
int s,i;
if (c<0) {
printf("ERROR\n");
}
s = 0;
for(i=0; i<c; ++i) {
s = s + b[i];
}
return s;
}
Теперь мы можем попытаться скомпилировать код:
junglefox@ubuntu:~$ gcc -c main.cpp
main.cpp: In function ‘int sum(int*, int)’:
main.cpp:20:1: error: the frame size of 32 bytes is larger than 1 bytes [-Werror=frame-larger-than=]
}
^
cc1plus: some warnings being treated as errors
junglefox@ubuntu:~$
который сообщает размер 32 байта.
- Альтернативным методом измерения размера стека является использование флага компилятора
stack-usage
в GCC. Итак, мы удаляем или комментируем строку // #pragma GCC diagnostic error "-Wframe-larger-than=1"
и пытаемся снова скомпилировать файл, как показано ниже.
junglefox@ubuntu:~$ gcc -c main.cpp -fstack-usage
Это создаст файл main.su
.
junglefox@ubuntu:~$ cat main.su
main.cpp:5:5:int sum(int*, int) 48 static
что показывает, что мы используем 48 байт стека.
Размер кучи
Чтобы узнать, какой размер кучи использует наша программа, мы воспользуемся инструментом valgrind
Massif
. Для этого нам сначала нужно добавить в наш код функцию main() (без которой мы не можем создать двоичный файл. А двоичный файл — это то, что нам нужно будет запускать с помощью valgrind). Итак, main.cpp
теперь выглядит так,
#include <stdio.h>
// #pragma GCC diagnostic error "-Wframe-larger-than=1"
int sum(int b[], int c) {
int s,i;
if (c<0) {
printf("ERROR\n");
}
s = 0;
for(i=0; i<c; ++i) {
s = s + b[i];
}
return s;
}
int main() {
// As Peter pointed, uncomment one of the following lines,
// for it to be a valid test. Also, compiler optimizations,
// when turned on, can give different results.
// sum(NULL,0);
// sum(NULL,-1);
return 0;
}
А теперь скомпилируем, соберем и запустим бинарник с помощью valgrind, как показано здесь:
junglefox@ubuntu:~$ gcc -o main main.cpp
junglefox@ubuntu:~$ valgrind ./main --tool=massif
Это сгенерирует кучу информации, которая выглядит примерно так:
==8179== Memcheck, a memory error detector
==8179== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8179== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8179== Command: ./main --tool=massif
==8179==
==8179==
==8179== HEAP SUMMARY:
==8179== in use at exit: 0 bytes in 0 blocks
==8179== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==8179==
==8179== All heap blocks were freed -- no leaks are possible
==8179==
==8179== For counts of detected and suppressed errors, rerun with: -v
==8179== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
который сообщает об общем использовании кучи 0 килобайт.
Кроме того, как пытался объяснить @mevets, вы всегда можете заглянуть в базовый код сборки, сгенерированный компилятором. В GCC вы могли бы сделать,
junglefox@ubuntu:~/gcc -S main.cpp
junglefox@ubuntu:~/cat main.s
который покажет вам, как выглядит ваша функция в базовом выводе сборки.
ПРИМЕЧАНИЕ/РЕДАКТИРОВАТЬ: Но чтобы быть полным, в C или C++, без динамического выделения памяти с использованием malloc()
или new
, вы, как программист, НЕ используете кучу. Кроме того, если вы не объявляете массив внутри своей функции, вы не используете какой-либо значительный объем стека.
Второй вопрос ОП:
Будет ли вызов функции из обработчика прерывания проблематичным или успешным?
Как многие люди любезно указали в комментариях, НЕ используйте printf()
в своем обработчике прерываний.
Цитата из этой ссылки:
Что отличает обработчики прерываний от других функций ядра, так это то, что ядро вызывает их в ответ на прерывания и что они выполняются в специальном контексте, называемом контекстом прерывания. Этот специальный контекст иногда называют атомарным контекстом, потому что код, выполняемый в этом контексте, не может быть заблокирован.
Поскольку прерывание может произойти в любое время, обработчик прерывания может быть выполнен в любое время. Крайне важно, чтобы обработчик работал быстро, чтобы возобновить выполнение прерванного кода как можно скорее.
Итак, помимо printf()
, одна вещь, которая может занять много времени, это размер массива, который вы передаете этой функции, когда используется как Interrupt Service Routine
. Он имеет сложность O(n)
. Если c
слишком велико, ваша программа будет остановлена на относительно долгое время, пока ISR не завершит выполнение этого цикла for()
.
03.01.2019
struct
локальными переменными. Вот почему код файловой системы Linux XFS часто является виновником проблем со стеком ядра. Очевидно, что рекурсия, которая не оптимизирована, может использовать огромное количество стека, поэтому не делайте этого. 03.01.2019valgrind
после добавления строкиsum(NULL, 0);
в функциюmain()
. На этот раз о выделении кучи сообщается как0
. На этот раз я тоже отключил оптимизацию. Я удалил строку, снова скомпилировал и снова запустил сvalgrind
, и я снова вижу использование кучи как0
. Либо я видел вещи раньше, либо компилятор творит здесь какое-то волшебство, поскольку ранее он сообщал об использовании кучи ~ 84 КБ. В качестве последнего теста я использовал эту строкуsum(NULL, -1);
в функцииmain()
, и теперь использование кучи точно равно 1 КБ - из-заprintf()
03.01.2019stdio.h
или код ссылки, содержащий ссылку наprintf
, glibc все равно инициализирует некоторые таблицы и буферы. 03.01.201932bytes
и48bytes
«довольно близки». Я не знаю никаких ограничений по времени, налагаемых на обслуживание прерываний. Что произойдет, так это то, что этот ISR заблокирует все остальное. Тогда вы можете потерять входящие данные, отправляемые другим оборудованием. Подробнее об этом здесь. Системы реального времени — это отдельная история. По поводу параметров X86 лучше задать отдельный вопрос. 04.01.2019