2012-03-12 2 views
0

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

Поскольку предполагаемый класс имеет такие простые требования к данным и ресурсов, я подумал, что можно было бы сделать класс «ориентированным на ценность», используя немодифицирующие операции и передавая экземпляры по значению, когда это разумно. Это будет простой класс, если он реализован, а не часть иерархии.

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

Я знаю, что сказано, что итераторы stl скомпилированы в простые операции с указателями и хотели бы сделать что-то подобное только с целыми операциями.

В любом случае библиотека будет обновлена ​​до C++ 11, так что я надеюсь, что по крайней мере с помощью constexpr и других новых функций, таких как ссылки rvalue, я могу приблизить производительность этого класса к чистых целых операций.

Кроме того, будут рекомендованы любые рекомендации по сравнительным характеристикам производительности между двумя реализациями.

+4

'constexpr' будет полезен, я сомневаюсь, что вы будете использовать ссылки rvalue, потому что ваш класс будет настолько дешевым, чтобы копировать в первую очередь. Используйте много инкрустаций, сохраняйте свои конструкторы и деструкторы тривиальными, и вы должны увидеть хорошую производительность. –

ответ

3

Что забавно с этим вопросом, что это именно так компилятор зависит. Использование Clang/LLVM:

#include <iostream> 
using namespace std; 

inline int foo(int a) { return a << 1; } 

struct Bar 
{ 
    int a; 

    Bar(int x) : a(x) {} 

    Bar baz() { return a << 1; } 
}; 

void out(int x) __attribute__ ((noinline)); 
void out(int x) { cout << x; } 

void out(Bar x) __attribute__ ((noinline)); 
void out(Bar x) { cout << x.a; } 

void f1(int x) __attribute ((noinline)); 
void f1(int x) { out(foo(x)); } 

void f2(Bar b) __attribute ((noinline)); 
void f2(Bar b) { out(b.baz()); } 

int main(int argc, char** argv) 
{ 
    f1(argc); 
    f2(argc); 
} 

дает the following IR:

define void @_Z3outi(i32 %x) uwtable noinline { 
    %1 = tail call %"class.std::basic_ostream"* 
       @_ZNSolsEi(%"class.std::basic_ostream"* @_ZSt4cout, i32 %x) 
    ret void 
} 

define void @_Z3out3Bar(i32 %x.coerce) uwtable noinline { 
    %1 = tail call %"class.std::basic_ostream"* 
       @_ZNSolsEi(%"class.std::basic_ostream"* @_ZSt4cout, i32 %x.coerce) 
    ret void 
} 

define void @_Z2f1i(i32 %x) uwtable noinline { 
    %1 = shl i32 %x, 1 
    tail call void @_Z3outi(i32 %1) 
    ret void 
} 

define void @_Z2f23Bar(i32 %b.coerce) uwtable noinline { 
    %1 = shl i32 %b.coerce, 1 
    tail call void @_Z3out3Bar(i32 %1) 
    ret void 
} 

И неудивительно, генерируемый сборка просто идентична:

.globl _Z2f1i 
    .align 16, 0x90 
    .type _Z2f1i,@function 
_Z2f1i:         # @_Z2f1i 
.Ltmp6: 
    .cfi_startproc 
# BB#0: 
    addl %edi, %edi 
    jmp _Z3outi     # TAILCALL 
.Ltmp7: 
    .size _Z2f1i, .Ltmp7-_Z2f1i 
.Ltmp8: 
    .cfi_endproc 
.Leh_func_end2: 


    .globl _Z2f23Bar 
    .align 16, 0x90 
    .type _Z2f23Bar,@function 
_Z2f23Bar:        # @_Z2f23Bar 
.Ltmp9: 
    .cfi_startproc 
# BB#0: 
    addl %edi, %edi 
    jmp _Z3out3Bar    # TAILCALL 
.Ltmp10: 
    .size _Z2f23Bar, .Ltmp10-_Z2f23Bar 
.Ltmp11: 
    .cfi_endproc 
.Leh_func_end3: 

Как правило, до тех пор, как методы класса являются inlined, параметр и ссылки this могут быть легко опущены. Я не совсем понимаю, как gcc может испортить это.

+0

«Как я научился перестать беспокоиться и доверять компилятору», я думаю. – metatheorem

+0

@metatheorem: в общем, вы должны доверять компилятору за мельчайшие детали. Для производительности вам лучше сконцентрироваться на ваших алгоритмах и вводе/выводе (диск, сеть, база данных, ...). Если вычисление происходит медленно, вам нужно будет профилировать и проверить, является ли это узким местом процессора или памяти, и, руководствуясь профилировщиком, попытайтесь улучшить его; но довольно редко идти на этот уровень. –

1

impleming фиксированной арифметику точки с семантикой значений даст худшую производительность, потому что ...

#include <iostream> 
using namespace std; 

inline int foo(int a) { return a << 1; } 

struct Bar 
{ 
    int a; 

    Bar(int x) : a(x) {} 

    Bar baz() { return a << 1; } 
}; 

void out(int x) __attribute__ ((noinline)); 
void out(int x) { cout << x; } 

void out(Bar x) __attribute__ ((noinline)); 
void out(Bar x) { cout << x.a; } 

void f1(int x) __attribute ((noinline)); 
void f1(int x) { out(foo(x)); } 

void f2(Bar b) __attribute ((noinline)); 
void f2(Bar b) { out(b.baz()); } 

int main(int argc, char** argv) 
{ 
    f1(argc); 
    f2(argc); 
} 

Теперь давайте посмотрим на разборку f1 и f2 ...

00000000004006e0 <f1(int)>: 
    4006e0: 01 ff     add edi,edi 
    4006e2: e9 d9 ff ff ff   jmp 4006c0 <out(int)> 
    4006e7: 66 0f 1f 84 00 00 00 nop WORD PTR [rax+rax*1+0x0] 
    4006ee: 00 00 

00000000004006f0 <f2(Bar)>: 
    4006f0: 48 83 ec 08    sub rsp,0x8 
    4006f4: 01 ff     add edi,edi 
    4006f6: e8 d5 ff ff ff   call 4006d0 <out(Bar)> 
    4006fb: 48 83 c4 08    add rsp,0x8 
    4006ff: c3      ret  

Как вы можете видеть, f2 имеет некоторые дополнительные беспорядки с указателем стека, который также препятствует тому, чтобы ret был удален.

(Это г ++ 4.6.1 на -O3)

+0

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

+0

Половина времени, когда я вижу результаты, подобные этому, есть некоторые тонкие проблемы, которые я упускал из виду (и часто могу исправить, когда они были обнаружены), а не просто« компилятор не обеспечивает такой хороший код, как вы думаете, это будет ». ... – Hurkyl

+0

Это краткий, если смутный ответ, и я получил тот же результат после разборки и игры с вашим кодом. Любая идея, что мешает оптимизации здесь? – metatheorem

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