जीसीसी 4.9 का उपयोग करना, Linaro toolchain का उपयोग कर एआरएम के लिए पार संकलन, मैं vector.assign()
परिवर्तन की संकलित परिणाम जब -std=c++14
जोड़ने में पाया है, एक तरीका है जो महत्व प्रदर्शन समस्याओं को बनाता है।std :: वेक्टर <uint8_t> मैन्युअल बजाय memcpy बुलाने की प्रतिलिपि बनाई जा रही है जब सी ++ 11/14 सक्षम
मैंने इस आवंटन + प्रतिलिपि करने के कई अलग-अलग तरीकों की कोशिश की है, लेकिन जब तक मैं std::vector
का उपयोग कर रहा हूं, तब तक उनमें से सभी को यह प्रदर्शन समस्या है।
मैं इस खिलौने उदाहरण के साथ समस्या को पुन: कर सकते हैं:
VectorTest.h
#include <stdint.h>
#include <stddef.h>
#include <vector>
struct VectorWrapper_t
{
VectorWrapper_t(uint8_t const* pData, size_t length);
std::vector<uint8_t> data;
};
VectorTest.cpp
#include "VectorTest.h"
VectorWrapper_t::VectorWrapper_t(uint8_t const* pData, size_t length)
{
data.assign(pData, pData + length);
}
जीसीसी झंडे:
असेंबली को देखते हुए, मैं देख सकता हूं कि मूल संस्करण (सी ++ 03, मुझे लगता है?) memmove
कहता है, जबकि सी ++ 14 संस्करण इसके बजाय एक अतिरिक्त लूप जोड़ता है जो ऐसा लगता है कि डेटा कॉपी करना है मैन्युअल रूप से। .loc
टैग देखकर gcc -fverbose-asm
के साथ जोड़ता है, इस लूप में दिए गए निर्देश stl_construct.h
और stl_uninitialized.h
से आते हैं।
जीसीसी 5.2.1 (सी ++ 14 के साथ) में बदलना, यह memmove
के बजाय memcpy
को छोड़कर, सी ++ 03 उदाहरण के लगभग समान रूप से संकलित करता है।
मैं के बजाय std::unique_ptr<uint8_t[]>
का उपयोग करके इस समस्या को हल करने में सक्षम हूं। हालांकि, मैं इस मुद्दे के निचले हिस्से में यह जानना चाहता हूं कि vector
एस का उपयोग करने वाले अन्य स्थानों में प्रदर्शन समस्याएं हो सकती हैं और उन्हें संभावित रूप से कैसे ठीक किया जा सकता है (जीसीसी 5.2 में अपडेट करना व्यावहारिक नहीं है)।
तो मेरा प्रश्न है: यह सी ++ 11/14 के तहत अलग-अलग संकलन क्यों करता है?
संदर्भ के लिए, gcc --version
रिपोर्ट:
arm-linux-gnueabihf-gcc (Linaro GCC 4.9-2014.12) 4.9.3 20141205 (prerelease)
।
यहाँ विधानसभा उत्पन्न जीसीसी है:
# C++03, gcc 4.9
push {r3, r4, r5, r6, r7, lr} @
movs r3, #0 @ tmp118,
mov r4, r0 @ this, this
str r3, [r0] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_start
mov r5, r2 @ length, length
str r3, [r0, #4] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
str r3, [r0, #8] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
cbnz r2, .L19 @ length,
mov r0, r4 @, this
pop {r3, r4, r5, r6, r7, pc} @
.L19:
mov r0, r2 @, length
mov r6, r1 @ pData, pData
bl _Znwj @
mov r2, r5 @, length
mov r1, r6 @, pData
mov r7, r0 @ D.13516,
bl memmove @
ldr r0, [r4] @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_start
cbz r0, .L3 @ D.13515,
bl _ZdlPv @
.L3:
add r5, r5, r7 @ D.13515, D.13516
str r7, [r4] @ D.13516, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_start
str r5, [r4, #4] @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_finish
mov r0, r4 @, this
str r5, [r4, #8] @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_end_of_storage
pop {r3, r4, r5, r6, r7, pc} @
.L6:
ldr r0, [r4] @ D.13515, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
cbz r0, .L5 @ D.13515,
bl _ZdlPv @
.L5:
bl __cxa_end_cleanup @
# C++14, gcc 4.9
push {r3, r4, r5, r6, r7, lr} @
movs r3, #0 @ tmp157,
mov r6, r0 @ this, this
str r3, [r0] @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_start
mov r5, r2 @ length, length
str r3, [r0, #4] @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
str r3, [r0, #8] @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
cbnz r2, .L25 @ length,
mov r0, r6 @, this
pop {r3, r4, r5, r6, r7, pc} @
.L25:
mov r0, r2 @, length
mov r4, r1 @ pData, pData
bl _Znwj @
adds r3, r4, r5 @ D.20345, pData, length
mov r7, r0 @ __result,
cmp r4, r3 @ pData, D.20345
ittt ne
addne r1, r4, #-1 @ ivtmp.76, pData,
movne r3, r0 @ __result, __result
addne r4, r0, r5 @ D.20346, __result, length
beq .L26 @,
.L7:
ldrb r2, [r1, #1]! @ zero_extendqisi2 @ D.20348, MEM[base: _48, offset: 0]
cbz r3, .L6 @ __result,
strb r2, [r3] @ D.20348, MEM[base: __result_23, offset: 0B]
.L6:
adds r3, r3, #1 @ __result, __result,
cmp r3, r4 @ __result, D.20346
bne .L7 @,
.L8:
ldr r0, [r6] @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_start
cbz r0, .L5 @ D.20346,
bl _ZdlPv @
.L5:
str r7, [r6] @ __result, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_start
mov r0, r6 @, this
str r4, [r6, #4] @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_finish
str r4, [r6, #8] @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_end_of_storage
pop {r3, r4, r5, r6, r7, pc} @
.L26:
adds r4, r0, r5 @ D.20346, __result, length
b .L8 @
.L11:
ldr r0, [r6] @ D.20346, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
cbz r0, .L10 @ D.20346,
bl _ZdlPv @
.L10:
bl __cxa_end_cleanup @
# C++14, gcc 5.2
push {r3, r4, r5, r6, r7, lr} @
movs r3, #0 @ tmp118,
mov r4, r0 @ this, this
str r3, [r0] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_start
str r3, [r0, #4] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
str r3, [r0, #8] @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
cbnz r2, .L19 @ length,
mov r0, r4 @, this
pop {r3, r4, r5, r6, r7, pc} @
.L19:
mov r0, r2 @, length
mov r6, r1 @ pData, pData
mov r5, r2 @ length, length
bl _Znwj @
mov r2, r5 @, length
mov r1, r6 @, pData
mov r7, r0 @ D.20824,
bl memcpy @
ldr r0, [r4] @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_start
cbz r0, .L3 @ D.20823,
bl _ZdlPv @
.L3:
add r5, r5, r7 @ D.20823, D.20824
str r7, [r4] @ D.20824, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_start
str r5, [r4, #4] @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_finish
mov r0, r4 @, this
str r5, [r4, #8] @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_end_of_storage
pop {r3, r4, r5, r6, r7, pc} @
.L6:
ldr r0, [r4] @ D.20823, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
cbz r0, .L5 @ D.20823,
bl _ZdlPv @
.L5:
bl __cxa_end_cleanup @
शायद यह कोई फर्क नहीं पड़ता है, लेकिन आरंभ करने के बजाय क्यों असाइन करें? उत्तरार्द्ध एक आवंटन से बच सकता है। 'वेक्टरवापर_टी (uint8_t const * pData, size_t लंबाई): डेटा (पीडीटा, पीडीटा + लंबाई) {}' – juanchopanza
यह प्रश्न लिनारो बग रिपोर्ट के लिए बेहतर अनुकूल लगता है। – ildjarn
2 संभावनाएं: या तो कोड समान होता है, लेकिन जीसीसी -5 + यह पता लगाता है कि लूप memcpy के बराबर है और इसे memcpy पर कॉल के साथ बदल देता है, या libstdC++ ने कुछ नया विशेष पथ प्राप्त किया जो memcpy को कॉल करता है। '-फडम्प-पेड़-सब' पास करने का प्रयास करें और यह निर्धारित करने के लिए कि क्या हो रहा है, कुछ शुरुआती/देर से डंप देखें। –