2012-12-08 11 views
6

मैं सीयूडीए को मौजूदा एकल थ्रेडेड सी प्रोग्राम में जोड़ने की कोशिश कर रहा हूं जो 90 के उत्तरार्ध में कभी-कभी लिखा गया था।जीसीसी और एनवीसीसी (जी ++) दो अलग-अलग संरचना आकार क्यों देखते हैं?

ऐसा करने के लिए मुझे दो भाषाओं, सी और सी ++ (एनवीसीसी एक सी ++ कंपाइलर) मिश्रण करने की आवश्यकता है।

समस्या यह है कि सी ++ कंपाइलर संरचना को एक निश्चित आकार के रूप में देखता है, जबकि सी संकलन एक ही संरचना को थोड़ा अलग आकार के रूप में देखता है। यह बुरी बात है। मैं वास्तव में इस से परेशान हूं क्योंकि मुझे 4 बाइट विसंगति का कोई कारण नहीं मिल रहा है।

/usr/lib/gcc/i586-suse-linux/4.3/../../../../i586-suse-linux/bin/ld: Warning: size of symbol `tree' changed from 324 in /tmp/ccvx8fpJ.o to 328 in gpu.o 

मेरे सी ++

#include <stdio.h> 
#include <stdlib.h> 
#include "assert.h" 
extern "C" 
{ 
#include "structInfo.h" //contains the structure declaration 
} 
... 

तरह लग रहा है और मेरी सी फ़ाइलों की तरह

struct TB { 
    int nbranch, nnode, root, branches[NBRANCH][2]; 
     double lnL; 
} tree; 
... 

मेरे मेकअप फ़ाइल

तरह लग रहा है की तलाश में की तरह

#include "structInfo.h" 
... 
structInfo.h साथ

देखो 012,

PRGS = prog 
CC = cc 
CFLAGS=-std=gnu99 -m32 
CuCC = nvcc 
CuFlags =-arch=sm_20 
LIBS = -lm -L/usr/local/cuda-5.0/lib -lcuda -lcudart 
all : $(PRGS) 
prog: 
     $(CC) $(CFLAGS) prog.c gpu.o $(LIBS) -o prog 
gpu.o: 
     $(CuCC) $(CuFlags) -c gpu.cu 

कुछ लोगों ने मुझसे पूछा कि मैंने एक अलग मेजबान संकलन विकल्प का उपयोग क्यों नहीं किया। मुझे लगता है कि 2 रिलीज पहले से मेजबान संकलन विकल्प को हटा दिया गया है? it never appeared to do what it said it would do भी। एक 4-बाइट संरेखण और कम से कम 8-बाइट संरेखण के साथ दूसरे के साथ काम कर रहा है:

nvcc warning : option 'host-compilation' has been deprecated and is ignored 
+0

क्या पैडिंग में अंतर मौजूद हो सकता है? क्या आप वाकई एनवीसीसी और जीसीसी (जो मुझे लगता है कि आप सीसी के रूप में उपयोग कर रहे हैं) संगत हैं? संपादित करें: असल में, एनवीसीसी के साथ पैडिंग मुद्दों से संबंधित कुछ पढ़ना, –

+0

द्वारा खड़े रहें क्या यह 32-बिट या 64-बिट प्लेटफार्म है? क्या आप कोशिश कर सकते हैं [पैरामीटर को चारों ओर ले जाना] (https://devtalk.nvidia.com/default/topic/394418/padding-problem-nvcc-bug-/) और देखें कि क्या यह काम करता है? –

+0

@EsaLakaniemi यह एक 32 बिट मंच है। – Mikhail

उत्तर

12

जीपीयू को सभी डेटा के लिए प्राकृतिक संरेखण की आवश्यकता होती है, उदा। एक 4-बाइट int को 4-बाइट सीमा से गठबंधन करने की आवश्यकता होती है और 8-बाइट डबल या लंबी लंबी 8-बाइट संरेखण की आवश्यकता होती है। CUDA होस्ट होस्ट के लिए यह भी लागू करता है ताकि यह सुनिश्चित किया जा सके कि कोड के होस्ट और डिवाइस भागों के बीच जितना संभव हो सके structs संगत हैं। दूसरी तरफ x86 CPUs को आमतौर पर डेटा को स्वाभाविक रूप से गठबंधन करने की आवश्यकता नहीं होती है (हालांकि प्रदर्शन जुर्माना संरेखण की कमी से हो सकता है)।

इस मामले में, CUDA एक 8 बाइट सीमा को struct के दोहरे घटक संरेखित करने के लिए की जरूरत है। चूंकि int घटकों की एक विषम संख्या डबल से आगे बढ़ती है, इसलिए इसे पैडिंग की आवश्यकता होती है। घटकों के क्रम को स्विच करना, यानी पहले डबल घटक डालना, मदद नहीं करता है क्योंकि इस तरह के structs की एक सरणी में प्रत्येक संरचना को 8-बाइट गठबंधन होना चाहिए और संरचना के आकार को पूरा करने के लिए 8 बाइट्स का एक होना चाहिए , जो पैडिंग की भी आवश्यकता है।

उसी तरह CUDA करता है के डबल्स संरेखित करने के लिए जीसीसी के लिए मजबूर करने के लिए, ध्वज -malign-double गुजरती हैं।

5

विभिन्न गद्दी 2 compilers द्वारा लागू की तरह लगता है। आपको संकलन-विशिष्ट #pragma निर्देशों द्वारा संरेखण को मजबूर करने में सक्षम होना चाहिए (विशिष्ट #pragma के बारे में अपने कंपाइलर दस्तावेज़ देखें)।

+0

'#pragma पैक (4)' और '#pragma पैक (8) 'मदद नहीं प्रतीत होता है, वे एक ही त्रुटि में परिणाम देते हैं। मैं जीसीसी के लिए यह कैसे कर सकता हूं? – Mikhail

+5

मुझे लगता है कि आपको जीसीसी के लिए क्या चाहिए, संकलक ध्वज -मल-डबल है। चूंकि जीपीयू को सभी डेटा के लिए प्राकृतिक संरेखण की आवश्यकता होती है, इसलिए सीयूडीए मेजबान पर यह भी सुनिश्चित करता है कि यह सुनिश्चित करने के लिए कि कोड कोड के मेजबान और डिवाइस भागों के बीच संगत है।चूंकि संरचना में डबल से पहले कीट की संख्या अजीब है, इसलिए इसे संरचना को पैड करने की आवश्यकता है। वैकल्पिक रूप से आप संरचना के घटकों को फिर से व्यवस्थित कर सकते हैं ताकि डबल पहला घटक हो। – njuffa

+0

@njuffa तो पुनर्मूल्यांकन काम नहीं करता है, लेकिन '-मलिन-डबल' काम करता है। आपको इसे एक उत्तर के रूप में पोस्ट करना चाहिए ताकि मैं आपको क्रेडिट दे सकूं। धन्यवाद! – Mikhail

2

इस बात की कोई गारंटी नहीं है कि दो अलग-अलग सी कंपाइलर एक ही प्रकार के समान प्रतिनिधित्व का उपयोग करेंगे - जब तक कि वे दोनों बाहरी बाहरी मानक (एबीआई) के अनुरूप न हों जो पर्याप्त विवरण में प्रतिनिधित्व निर्दिष्ट करता है।

यह पैडिंग में सबसे अधिक संभावना है, जहां एक कंपाइलर को double की आवश्यकता होती है ताकि 4-बाइट गठबंधन हो और दूसरे को 8-बाइट गठबंधन की आवश्यकता हो। सी और सी ++ मानकों के संबंध में दोनों विकल्प पूरी तरह मान्य हैं।

आप आकार और अपने संरचना के सभी सदस्यों की ऑफसेट बाहर मुद्रण द्वारा और अधिक विस्तार से इसकी जांच कर सकते हैं:

printf("nbranch: size %3u offset %3u\n", 
     (unsigned)sizeof tree.nbranch, 
     (unsigned)offsetof(struct TB, nbranch)); 
/* and similarly for the other members */ 

वहाँ एक अलग संरेखण निर्दिष्ट करने के लिए एक संकलक विशिष्ट तरीका हो सकता है, लेकिन ऐसी तकनीकें not always safe हैं।

आदर्श समाधान सी और सी ++ कोड के लिए एक ही कंपाइलर का उपयोग करना होगा। सी सी ++ का सबसेट नहीं है, लेकिन आम तौर पर मौजूदा सी कोड को संशोधित करना बहुत मुश्किल नहीं होना चाहिए, इसलिए यह सी ++ के रूप में संकलित होता है।

या आप अपनी संरचना परिभाषा को पुनर्व्यवस्थित करने में सक्षम हो सकते हैं ताकि दोनों कंपाइलर्स इसे उसी तरह से बाहर रख सकें। double सदस्य को पहले रखने की संभावना है। यह अभी भी काम करने की गारंटी नहीं है, और यह या तो कंपाइलर के भविष्य के संस्करणों के साथ तोड़ सकता है, लेकिन यह शायद पर्याप्त है।

भूल वहाँ भी संरचना के अंत में गद्दी हो सकता है कि मत करो; संरचनाओं के सरणी के लिए उचित संरेखण की गारंटी देने के लिए कभी-कभी यह आवश्यक होता है। sizeof (struct TB) पर देखें और इसे अंतिम घोषित सदस्य के आकार और ऑफसेट से तुलना करें।

एक और संभावना: डालें स्पष्ट अप्रयुक्त सदस्यों के लिए एक सुसंगत संरेखण के लिए मजबूर करने। उदाहरण के लिए, यदि आपके पास लगता है:

struct foo { 
    uint16_t x; 
    uint32_t y; 
}; 

और एक संकलक 16 बिट पर y डालता है, और अन्य 32 बिट पर कहते गद्दी के 16 बिट्स के साथ। आप परिभाषा को बदलते हैं तो:

struct foo { 
    uint16_t x; 
    uint16_t unused_padding; 
    uint32_t y; 
}; 

तो आप अधिक x और y ही दोनों compilers के तहत ऑफसेट है होने की संभावना हो। यह सुनिश्चित करने के लिए कि आपको सबकुछ सुसंगत है, आपको अभी भी प्रयोग करना होगा।

C और C++ कोड के बाद से (है ना?), तो आपको बाइट क्रम अलग तरह चीजों के बारे में चिंता करने की ज़रूरत नहीं होना चाहिए एक ही कार्यक्रम का हिस्सा बनने जा रहे हैं। यदि आप अलग-अलग प्रोग्रामों के बीच अपने संरचना प्रकार के मानों को प्रेषित करना चाहते हैं, तो उन्हें फ़ाइलों में संग्रहीत करके या नेटवर्क पर प्रसारित करके कहें, आपको संरचना मूल्य को बाइट्स के अनुक्रम में क्रमबद्ध करने के लिए एक निरंतर तरीका परिभाषित करने की आवश्यकता हो सकती है और इसके विपरीत।

संबंधित मुद्दे