Чтобы развить то, на что уже указывали другие пользователи, я постараюсь ответить на оба вопроса ОП.
Первый вопрос ОП:
Я хотел бы знать, сколько стека и кучи в байтах требуется для
сумма функций в платформе 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()
.