İşaretçi ile türetilmiş bir dizi kullanılırken fortran'da bellek kullanımı


13

Bu örnek programda aynı şeyi (en azından öyle düşünüyorum) iki farklı şekilde yapıyorum. Bunu Linux bilgisayarımda çalıştırıyorum ve üstte bellek kullanımını izliyorum. Gfortran kullanarak, birinci şekilde ("1" ve "2" arasında) kullanılan belleğin 8.2GB, ikinci şekilde ("2" ve "3" arasında) bellek kullanımının 3.0GB olduğunu düşünüyorum. Intel derleyici ile fark daha da büyük: 10GB ve 3GB. Bu, işaretçileri kullanmak için aşırı bir ceza gibi görünüyor. Bu neden oluyor?

program test
implicit none

  type nodesType
    integer:: nnodes
    integer,dimension(:),pointer:: nodes 
  end type nodesType

  type nodesType2
    integer:: nnodes
    integer,dimension(4):: nodes 
  end type nodesType2

  type(nodesType),dimension(:),allocatable:: FaceList
  type(nodesType2),dimension(:),allocatable:: FaceList2

  integer:: n,i

  n = 100000000

  print *, '1'
  read(*,*)
  allocate(FaceList(n))
  do i=1,n
    FaceList(i)%nnodes = 4
    allocate(FaceList(i)%nodes(4))
    FaceList(i)%nodes(1:4) = (/1,2,3,4/)
  end do
  print *, '2'
  read(*,*)

  do i=1,n
    deallocate(FaceList(i)%nodes)
  end do
  deallocate(FaceList)

  allocate(FaceList2(n))
  do i=1,n
    FaceList2(i)%nnodes = 4
    FaceList2(i)%nodes(1:4) = (/1,2,3,4/)
  end do
  print *, '3'
  read(*,*)

end program test

Arka plan yerel ızgara ayrıntılandırmasıdır. Yüzleri kolayca eklemek ve kaldırmak için bağlantılı listeyi seçtim. Düğüm sayısı varsayılan olarak 4'tür, ancak yerel ayrıntılandırmalara bağlı olarak daha yüksek olabilir.


1
Gördüğünüz performans farkının yanı sıra, sızıntılara eğilimli olabildiğince "ilk yoldan" kaçınılmalıdır. Bunu kullanmanın tek nedeni Fortran 95'e sıkı sıkıya bağlı kalmak olacaktır. Türetilmiş tiplerdeki allocatable'lar TR 15581'e eklenmiştir, ancak tüm Fortran derleyicileri (2003 özelliklerine sahip olmayanlar bile) bunları desteklemiştir, yani F95 + TR15581 + TR15580 sonsuza dek .
stali

1
Bunu yapmanın nedeni, bazı yüzlerin 4'ten fazla düğüme sahip olabilmesidir.
chris

O zaman kesinlikle mantıklı. 4'ün sabit olduğunu varsaydım.
stali

Yanıtlar:


6

Aslında fortran derleyicilerinin nasıl çalıştığını bilmiyorum, ancak dil özelliklerine dayanarak bir tahmin yapabilirim.

Fortran'daki dinamik diziler, şekil, boyut, lbound, ubound ve tahsis edilmiş veya ilişkilendirilmiş (ayrıştırılabilir ve işaretçiler) gibi iç işlevlerle çalışmak için meta verilerle birlikte gelir. Büyük diziler için meta verilerin boyutu önemsizdir, ancak küçük diziler için, sizin durumunuzda olduğu gibi, toplanabilir. Sizin durumunuzda, 4 boyutlu dinamik dizilerin gerçek verilerden daha fazla meta verisi olabilir ve bu da bellek kullanım balonunuza yol açar.

Yapılarınızın altındaki dinamik belleğe şiddetle tavsiye ediyorum. Belirli sayıda boyutta fiziksel sistemlerle ilgilenen bir kod yazıyorsanız, bunu bir makro olarak ayarlayabilir ve yeniden derleyebilirsiniz. Grafiklerle uğraşıyorsanız, kenar sayısı veya benzerleri üzerinde statik olarak bir üst sınır ayırabilirsiniz. Gerçekten ince taneli dinamik bellek kontrolüne ihtiyaç duyan bir sistemle uğraşıyorsanız, muhtemelen C'ye geçmek en iyisidir.


Evet ama meta veri argümanı her iki durum için de geçerli değil mi?
stali

@stali no, ikinci nyöntemin, birinci yöntemin ihtiyaç duyduğu işaretçilerin aksine bir işaretçi gerektirdiğine dikkat edin .
Aron Ahmadia

Bazı arka plan bilgileri ekledim. Statik olarak bir üst sınırı tahsis etme öneriniz zaten iyi bir gelişmedir. Üst bağlı 8, ama hafıza hala boşa Yani çoğunluk, sadece küçük bir yüzdesi 5,6,7 veya 8. sahip olacak 4 olacak ...
Chris

@chris: Biri 4, diğeri 8 düğümlü iki liste yapabilir misiniz?
Pedro

Muhtemelen. İyi bir uzlaşma gibi görünüyor.
chris

5

As maxhutch sivri out vardır, sorun ayrı bellek tahsisatı sayısının çokluğu muhtemelen. Bununla birlikte, meta verilerin üstünde, muhtemelen bellek yöneticisinin ihtiyaç duyduğu ek veri ve hizalama vardır, yani muhtemelen her ayırmayı 64 bayt veya daha fazla katına yuvarlamaktadır.

Her düğüm için küçük bir yığın ayırmaktan kaçınmak için, her düğüme önceden ayrılmış bir dizinin bir bölümünü ayırmayı deneyebilirsiniz :

integer :: finger
indeger, dimension(8*n) :: theNodes

finger = 1
do i=1,n
    FaceList(i)%nodes => theNodes(finger:finger+FaceList(i)%nnodes-1)
    finger = finger + FaceList(i)%nnodes
end do

Fortran'ım biraz paslı, ancak prensipte değilse yukarıdakilerin çalışması gerekir.

Fortran derleyicinizin bir POINTER türü için saklaması gerektiğini düşündüğü her şeyin ek yüküne sahip olacaksınız, ancak bellek yöneticisi ek yüklerine sahip olmayacaksınız.


bu sadece biraz yardımcı olur. Sorun, tek bir işaretçi değil, dinamik bir işaretçi dizisidir: FaceList (i)% düğüm (1: FaceList (i)% nnodes) => Düğümler (parmak: parmak + FaceList (i)% düğümler-1). Ayrıca, önceden ayrılmış dizinin boyutu için keskin bir tahmin anlamına gelir.
chris

@chris: Tamamen anladığımdan emin değilim ... "Dinamik işaretçi dizisi" ile ne demek istiyorsun? Alan nodesType%nodes, dinamik bir dizinin işaretçisidir.
Pedro

0

Ah. Bu yaşadığım problemle aynı. Bu soru çok eski, ama biraz farklı bir kod stili öneriyorum. Benim sorunum, takip kodu olarak türetilmiş veri türünde ayrılabilir ifade dizisi oldu.

type :: node
  real*4,dimension(:),allocatable :: var4
  real*8,dimension(:),allocatable :: var8
end type node

type(node),dimension(:),allocatable :: nds

imax = 5000
allocate(nds(imax))

Bazı testlerden, türetilmiş ifadeyi veya işaretçi ifadesini türetilmiş tipte dört durumda takip kodu olarak kullanırsam, bellek sızıntısının çok büyük olduğunu doğruladım. Benim durumumda, 520MB boyutundaki dosyayı kırmızıya dönüştürdüm. Ancak intel fortran karşılaştırıcısında bellek kullanımı 4GB'dı. Bu 8 kat daha büyük!

!(case 1) real*4,dimension(:),allocatable :: var4
!(case 2) real*4,dimension(:),pointer :: var4
!(case 3) real*4,allocatable :: var4(:,:)

!(case 4) 
type :: node(k)
  integer,len :: k = 4
  real*4 :: var4(k)
end type node

Türetilmiş tip olmadan ayrılabilir veya işaretçi deyimi kullandığımda bellek sızıntısı oluşmuyor. Bence, türetilmiş tipte ayrılabilir veya işaretçi türü değişkeni bildirirsem ve türetilmiş tipte büyük türetilmiş tip değişkenini ayrılan değişken olarak ayırırsam, memeory sızıntısı oluşur. Bu sorunu çözmek için, tür kodu takip kodu olarak türetilmemiş kodumu değiştirdim.

real*4,dimension(:,:),allocatable :: var4 
! array index = (Num. of Nodes, Num. of Variables)

ya da bu tarz?

integer,dimension(:),allocatable :: NumNodes ! (:)=Num. of Cell or Face or etc.
integer,dimension(:),allocatable :: Node     ! (:)=(Sum(NumNodes))

NumNodes değişkeni, her bir yüzdeki düğüm sayısı anlamına gelir ve Düğüm değişkeni, NumNodes değişkeniyle eşleşen düğüm numaralarıdır. Belki de bu kod tarzında bellek sızıntısı oluşmadığını düşünüyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.