2015-11-20 2 views
1

У меня есть существующая кодовая база Fortran, с которой я работаю, и она довольно большая. Я не программист Фортран, поэтому я знаю, что здесь я не делаю все правильно.Фортран и C Смешанное программирование (общая память)

Я пытаюсь создать и инициализировать массив из 1,6 миллиона целых чисел. Я не могу заставить это инициализировать в Fortran (используя ifort или gfort), поскольку у меня либо будет слишком много продолжений строк, либо слишком длинных строк.

Так что, естественно, я переключился на C и написал функцию, чтобы просто инициализировать массив, и он скомпилирован в секундах без проблем. Теперь я пытаюсь связать их вместе. Для упрощения вещей я создал небольшой тестовый пример. Вот три файла, с которыми я работаю:

init.c

void c_init_() 
{ 
    static const int f_init_g[1600000] = 
    { 
    3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326, 
    25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806, 
    --------------------------------------------------------------------- 
    25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806 
    }; 
} 

init_mod.f90

MODULE INIT_MOD 

    USE, INTRINSIC :: ISO_C_BINDING 
    IMPLICIT NONE 
    SAVE 

    TYPE :: INIT_TYPE 
    INTEGER (C_INT), DIMENSION(1600000) :: INIT 
    END TYPE INIT_TYPE 
    TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP 
    TYPE (INIT_TYPE), POINTER :: INIT_FP 

END MODULE INIT_MOD 

main.f90

PROGRAM INIT 

    USE INIT_MOD 
    USE, INTRINSIC :: ISO_C_BINDING 

    TYPE (INIT_TYPE) :: INIT_T 
    CALL c_init() 
    CALL C_F_POINTER(INIT_CP,INIT_FP) 
    INIT_T = INIT_FP 

    END PROGRAM INIT 

компилировать это с помощью следующие команды:

icc -c init.c 
ifort -c init_mod.f90 
ifort main.f90 init_mod.o init.o 

У меня возникает ошибка сегментации при работе, потому что INIT_CP указывает на ничего, насколько я могу судить. Я знаю, что не получаю INIT_CP, чтобы указать на массив в моей функции C. Поэтому я пытаюсь понять, как это сделать.

Я бы хотел, чтобы у кого-то было предложение о том, как инициализировать этот массив изначально в Фортране. Мой последний вариант, который я сделаю, это сделать небольшую инициализацию этого массива в сборке и написать сценарий для генерации кода сборки для инициализации этого массива (на основе сборки из небольшой инициализации я могу имитировать одно и то же для любого размера массив). Я не так взволнован, чтобы сделать это, но это может быть самое простое и надежное решение.

Самое главное, что мне нужны другие подпрограммы Fortran, которые используют этот массив, чтобы увидеть, что он является статичным по форме и значению, чтобы можно было выполнить соответствующие процедурные оптимизации.

+0

Является ли несоответствие длины массива (1600000 против 1605320) умышленным? – fuz

+0

Совсем нет. Просто исправил, что спасибо. – Jimmy

+0

Решает ли это нарушение сегментации? – fuz

ответ

5

Фортран-С Взаимодействующие переменные должны иметь внешнюю связь. Как было предложено другими в комментариях, переместите объявление C в область файла и потеряйте спецификатор static.

Нет необходимости в промежуточном C_PTR - переменная массива Fortran напрямую взаимодействует с соответствующим массивом C.

Уменьшение размера массива незначительно:

/* C File scope */ 
const int f_init_g[3] = { 101, 102, 103 }; 

! Fortran 
MODULE m 
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT 
    IMPLICIT NONE 
    INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3) 
END MODULE m 

PROGRAM p 
    USE m 
    IMPLICIT NONE 
    PRINT *, f_init_g(2) 
END PROGRAM p 

Обратите внимание, что исходная посылка - что невозможно определить или инициализировать такой массив внутри Fortran только - ложна. Правила вокруг постоянных выражений в Fortran позволяют ссылаться на существующие именованные константы, включая именованные константы, которые являются массивами. Если вы решили упорствовать с этим безумием, и предполагая, что значение инициализатора не может быть описаны каким-то выражение, рассмотрит:

INTEGER, PARAMETER :: first(10) & 
    = [ 3263, 322,  3261, 60,  32249, & 
     32244, 3229, 23408, 252407, 25326 ] 
INTEGER, PARAMETER :: second(10) & 
    = [ 25805, 25723, 25562, 25787, 4549, & 
     32248, 32244, 32243, 253207, 21806] 
... 
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ] 

Вы, вероятно, потребуются промежуточные именованные постоянные массивы до финального конструктора массива.

В приведенной выше таблице f_init_g является именованной константой, которая очень хорошо видна компилятору и, скорее всего, приведет к оптимизации, которую вы ищете.

Однако вы можете столкнуться с ограничениями на сложность компилятора, которые нарушают этот последний подход.

Когда f_init_g является переменной, инициализированной C, вы в основном полагаетесь на возможности межязыковой и межпроцессной оптимизации вашего набора инструментов, и если эти возможности даже существуют, я бы не ожидал от них многого для этого дело. Я ожидаю, что вы не потеряете много производительности, за одноразовое время для ввода-вывода, если вы прочитаете значение массива из файла во время выполнения.

+0

Спасибо! Это тот тип ответа, который я искал. Мне просто нужно было знать, как это сделать в Фортране. Существует не простое выражение, которое может инициализировать этот массив, и зная его во время компиляции, это действительно поможет мне немного. Я ценю помощь. – Jimmy

Смежные вопросы