jaki jest wpływ na wydajność stosowania int64 t zamiast int32 T w systemach 32-bitowych?

Nasza biblioteka C++ używa obecnie time_t do przechowywania wartości czasu. W niektórych miejscach zaczynam potrzebować dokładności poniżej sekundy, więc i tak potrzebny będzie większy typ danych. Przydałoby się również obejście problemu z rokiem 2038 w niektórych miejscach. Myślę więc o całkowitym przejściu na jedną klasę Czasu z podstawową wartością int64_t, aby zastąpić wartość time_t we wszystkich miejscach.

Teraz zastanawiam się nad skutkami takiej zmiany podczas uruchamiania tego kod na 32-bitowym systemie operacyjnym lub 32-bitowym procesorze. Ibuc kompilator wygeneruje kod do wykonywania 64-bitowej arytmetyki przy użyciu 32-bitowych rejestrów. Ale jeśli jest to zbyt wolne, być może będę musiał użyć bardziej zróżnicowanego sposobu radzenia sobie z wartościami czasu, co może utrudnić utrzymanie oprogramowania.

Co mnie interesuje:

  • jakie czynniki wpływają na wydajność tych operacji? Prawdopodobnie wersja kompilatora i kompilatora; ale czy system operacyjny lub procesor marka / model również na to wpływa? Czy normalny 32-bitowy system wykorzysta 64-bitowe rejestry nowoczesnych procesorów?
  • które operacje będą szczególnie powolne, gdy emulowane na 32-bitach? Lub który nie będzie miał prawie żadnego spowolnienia?
  • czy istnieją jakieś wyniki testów porównawczych dla użycia int64_t/uint64_t w systemach 32-bitowych?
  • czy ktoś ma własne doświadczenie na temat tego wpływu na wydajność?

Interesuje mnie głównie g++ 4.1 i 4.4 na Linuksie 2.6 (RHEL5, RHEL6) na Intel Core 2 systemów; ale dobrze byłoby też wiedzieć o sytuacji w innych systemach (np. Sparc Solaris + Solaris CC, Windows + MSVC).

Author: oliver, 2013-05-30

4 answers

Jakie czynniki wpływają na wydajność tych operacji? Prawdopodobnie kompilatora i wersji kompilatora; ale czy system operacyjny lub Na to również wpływa marka/model procesora?

Głównie architektura procesora (i model - proszę przeczytać model, gdzie wspominam architekturę procesora w tej sekcji). Kompilator może mieć pewien wpływ, ale większość kompilatorów robi to całkiem dobrze, więc architektura procesora będzie miała większy wpływ niż kompilator.

System operacyjny nie będzie miał żadnego wpływu (poza "jeśli zmienisz system operacyjny, musisz użyć innego typu kompilatora, który zmienia to, co robi kompilator" w niektórych przypadkach - ale to prawdopodobnie mały efekt).

Czy normalny 32-bitowy system będzie używał 64-bitowych rejestrów nowoczesnych procesorów?

To niemożliwe. Jeśli system jest w trybie 32-bitowym, będzie działał jako system 32-bitowy, dodatkowe 32-bitowe rejestry są całkowicie niewidoczne, tak jak to byłoby, gdyby system był faktycznie "prawdziwym 32-bitowym systemem".

Które operacje będą szczególnie powolne, gdy emulowane na 32-bitach? Lub który nie będzie miał prawie żadnego spowolnienia?

Dodawanie i odejmowanie, jest gorsze, ponieważ muszą być wykonywane w sekwencji dwóch operacji, a druga operacja wymaga wykonania pierwszej - nie jest tak, jeśli kompilator produkuje tylko dwie operacje dodawania na niezależnych danych.

Mulitplikacja będzie dużo gorzej, jeśli parametry wejściowe są rzeczywiście 64-bitowe - więc 2^35 * 83 jest gorszy niż 2^31 * 2^31, na przykład. Wynika to z faktu, że procesor może produkować 32 x 32 bitów pomnożyć do wyniku 64-bitowego dość dobrze - około 5-10 cykli zegara. Ale mnożenie bitów 64 x 64 wymaga sporej ilości dodatkowego kodu, więc potrwa dłużej.

Dzielenie jest problemem podobnym do mnożenia - ale tutaj można wziąć 64-bitowe wejście z jednej strony, podzielić je przez wartość 32-bitową i uzyskać wartość 32-bitową. Ponieważ trudno przewidzieć, kiedy to zadziała, podział 64-bitowy jest prawdopodobnie prawie zawsze powolny.

Dane będą również zajmować dwa razy więcej miejsca w pamięci podręcznej, co może mieć wpływ na wyniki. I w podobnej konsekwencji, ogólne przydzielanie i przekazywanie danych będzie trwało dwa razy dłużej niż minimum, ponieważ jest dwa razy więcej danych do pracy.

Kompilator będzie również musiał użyć większej liczby rejestrów.

Czy istnieją jakieś istniejące wyniki testów porównawczych do wykorzystania int64_t/uint64_t na systemach 32-bitowych?

Prawdopodobnie, ale nie jestem tego świadoma. A nawet jeśli są, byłoby to tylko w pewnym sensie znaczące dla Ciebie, ponieważ mieszanka operacji jest bardzo krytyczna dla szybkości operacji.

Jeśli wydajność jest ważną częścią twojej aplikacji, porównuj swój kod (lub jego reprezentatywną część). Nie ma znaczenia, czy Benchmark X daje 5%, 25% czy 103% wolniejsze wyniki, Czy twój kod jest nieco wolniejszy albo szybciej w tych samych okolicznościach.

Czy ktoś ma własne doświadczenie na temat tego wpływu na wydajność?

Przekompilowałem kod, który używa 64-bitowych liczb całkowitych dla architektury 64-bitowej i stwierdziłem, że wydajność poprawia się o pewną znaczną ilość-aż o 25% na niektórych bitach kodu.

Zmiana systemu operacyjnego na 64-bitową wersję tego samego systemu, może pomoże?

Edit:

Ponieważ lubię dowiedzieć się, jaka jest różnica w tego rodzaju rzeczy, napisałem trochę kodu i z jakimś prymitywnym szablonem (wciąż ucząc się, że szablony bitowe nie są dokładnie moim najgorętszym tematem, muszę powiedzieć-Daj mi arytmetykę bitową i wskaźnikową, a (zazwyczaj) poprawię to... )

Oto kod, który napisałem, próbując odtworzyć kilka popularnych funktonów:

#include <iostream>
#include <cstdint>
#include <ctime>

using namespace std;

static __inline__ uint64_t rdtsc(void)
{
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
}

template<typename T>
static T add_numbers(const T *v, const int size)
{
    T sum = 0;
    for(int i = 0; i < size; i++)
    sum += v[i];
    return sum;
}


template<typename T, const int size>
static T add_matrix(const T v[size][size])
{
    T sum[size] = {};
    for(int i = 0; i < size; i++)
    {
    for(int j = 0; j < size; j++)
        sum[i] += v[i][j];
    }
    T tsum=0;
    for(int i = 0; i < size; i++)
    tsum += sum[i];
    return tsum;
}



template<typename T>
static T add_mul_numbers(const T *v, const T mul, const int size)
{
    T sum = 0;
    for(int i = 0; i < size; i++)
    sum += v[i] * mul;
    return sum;
}

template<typename T>
static T add_div_numbers(const T *v, const T mul, const int size)
{
    T sum = 0;
    for(int i = 0; i < size; i++)
    sum += v[i] / mul;
    return sum;
}


template<typename T> 
void fill_array(T *v, const int size)
{
    for(int i = 0; i < size; i++)
    v[i] = i;
}

template<typename T, const int size> 
void fill_array(T v[size][size])
{
    for(int i = 0; i < size; i++)
    for(int j = 0; j < size; j++)
        v[i][j] = i + size * j;
}




uint32_t bench_add_numbers(const uint32_t v[], const int size)
{
    uint32_t res = add_numbers(v, size);
    return res;
}

uint64_t bench_add_numbers(const uint64_t v[], const int size)
{
    uint64_t res = add_numbers(v, size);
    return res;
}

uint32_t bench_add_mul_numbers(const uint32_t v[], const int size)
{
    const uint32_t c = 7;
    uint32_t res = add_mul_numbers(v, c, size);
    return res;
}

uint64_t bench_add_mul_numbers(const uint64_t v[], const int size)
{
    const uint64_t c = 7;
    uint64_t res = add_mul_numbers(v, c, size);
    return res;
}

uint32_t bench_add_div_numbers(const uint32_t v[], const int size)
{
    const uint32_t c = 7;
    uint32_t res = add_div_numbers(v, c, size);
    return res;
}

uint64_t bench_add_div_numbers(const uint64_t v[], const int size)
{
    const uint64_t c = 7;
    uint64_t res = add_div_numbers(v, c, size);
    return res;
}


template<const int size>
uint32_t bench_matrix(const uint32_t v[size][size])
{
    uint32_t res = add_matrix(v);
    return res;
}
template<const int size>
uint64_t bench_matrix(const uint64_t v[size][size])
{
    uint64_t res = add_matrix(v);
    return res;
}


template<typename T>
void runbench(T (*func)(const T *v, const int size), const char *name, T *v, const int size)
{
    fill_array(v, size);

    uint64_t long t = rdtsc();
    T res = func(v, size);
    t = rdtsc() - t;
    cout << "result = " << res << endl;
    cout << name << " time in clocks " << dec << t  << endl;
}

template<typename T, const int size>
void runbench2(T (*func)(const T v[size][size]), const char *name, T v[size][size])
{
    fill_array(v);

    uint64_t long t = rdtsc();
    T res = func(v);
    t = rdtsc() - t;
    cout << "result = " << res << endl;
    cout << name << " time in clocks " << dec << t  << endl;
}


int main()
{
    // spin up CPU to full speed...
    time_t t = time(NULL);
    while(t == time(NULL)) ;

    const int vsize=10000;

    uint32_t v32[vsize];
    uint64_t v64[vsize];

    uint32_t m32[100][100];
    uint64_t m64[100][100];


    runbench(bench_add_numbers, "Add 32", v32, vsize);
    runbench(bench_add_numbers, "Add 64", v64, vsize);

    runbench(bench_add_mul_numbers, "Add Mul 32", v32, vsize);
    runbench(bench_add_mul_numbers, "Add Mul 64", v64, vsize);

    runbench(bench_add_div_numbers, "Add Div 32", v32, vsize);
    runbench(bench_add_div_numbers, "Add Div 64", v64, vsize);

    runbench2(bench_matrix, "Matrix 32", m32);
    runbench2(bench_matrix, "Matrix 64", m64);
}

Zestawione z:

g++ -Wall -m32 -O3 -o 32vs64 32vs64.cpp -std=c++0x

A wyniki są następujące: Uwaga: Patrz wyniki 2016 poniżej - wyniki te są nieco optymistyczne ze względu na różnicę w użyciu instrukcji SSE w trybie 64-bitowym, ale bez użycia SSE w trybie 32-bitowym.

result = 49995000
Add 32 time in clocks 20784
result = 49995000
Add 64 time in clocks 30358
result = 349965000
Add Mul 32 time in clocks 30182
result = 349965000
Add Mul 64 time in clocks 79081
result = 7137858
Add Div 32 time in clocks 60167
result = 7137858
Add Div 64 time in clocks 457116
result = 49995000
Matrix 32 time in clocks 22831
result = 49995000
Matrix 64 time in clocks 23823

Jak widzisz, dodawanie i mnożenie nie jest o wiele gorsze. Sekcja jest bardzo zła. Co ciekawe, dodatek matrycy nie jest w ogóle dużą różnicą.

I czy jest szybszy na 64-bitach słyszałem, że niektórzy z was pytają: Używając tych samych opcji kompilatora, po prostu -M64 zamiast - M32-yupp, dużo szybciej:

result = 49995000
Add 32 time in clocks 8366
result = 49995000
Add 64 time in clocks 16188
result = 349965000
Add Mul 32 time in clocks 15943
result = 349965000
Add Mul 64 time in clocks 35828
result = 7137858
Add Div 32 time in clocks 50176
result = 7137858
Add Div 64 time in clocks 50472
result = 49995000
Matrix 32 time in clocks 12294
result = 49995000
Matrix 64 time in clocks 14733

Edit, update for 2016: cztery warianty, z i bez SSE, w 32-i 64-bitowy tryb kompilatora.

Zazwyczaj używam clang++ jako mojego zwykłego kompilatora w dzisiejszych czasach. Próbowałem kompilować z g++ (ale nadal będzie to inna wersja niż wyżej, ponieważ zaktualizowałem swój komputer - i mam inny procesor też). Ponieważ g++ nie udało się skompilować wersji no-sse w 64-bitowej, nie widziałem w tym sensu. (g++ daje podobne wyniki i tak)

Jako krótka tabela:

Test name      | no-sse 32 | no-sse 64 | sse 32 | sse 64 |
----------------------------------------------------------
Add uint32_t   |   20837   |   10221   |   3701 |   3017 |
----------------------------------------------------------
Add uint64_t   |   18633   |   11270   |   9328 |   9180 |
----------------------------------------------------------
Add Mul 32     |   26785   |   18342   |  11510 |  11562 |
----------------------------------------------------------
Add Mul 64     |   44701   |   17693   |  29213 |  16159 |
----------------------------------------------------------
Add Div 32     |   44570   |   47695   |  17713 |  17523 |
----------------------------------------------------------
Add Div 64     |  405258   |   52875   | 405150 |  47043 |
----------------------------------------------------------
Matrix 32      |   41470   |   15811   |  21542 |   8622 |
----------------------------------------------------------
Matrix 64      |   22184   |   15168   |  13757 |  12448 |

Pełne wyniki z opcjami kompilacji.

$ clang++ -m32 -mno-sse 32vs64.cpp --std=c++11 -O2
$ ./a.out
result = 49995000
Add 32 time in clocks 20837
result = 49995000
Add 64 time in clocks 18633
result = 349965000
Add Mul 32 time in clocks 26785
result = 349965000
Add Mul 64 time in clocks 44701
result = 7137858
Add Div 32 time in clocks 44570
result = 7137858
Add Div 64 time in clocks 405258
result = 49995000
Matrix 32 time in clocks 41470
result = 49995000
Matrix 64 time in clocks 22184

$ clang++ -m32 -msse 32vs64.cpp --std=c++11 -O2
$ ./a.out
result = 49995000
Add 32 time in clocks 3701
result = 49995000
Add 64 time in clocks 9328
result = 349965000
Add Mul 32 time in clocks 11510
result = 349965000
Add Mul 64 time in clocks 29213
result = 7137858
Add Div 32 time in clocks 17713
result = 7137858
Add Div 64 time in clocks 405150
result = 49995000
Matrix 32 time in clocks 21542
result = 49995000
Matrix 64 time in clocks 13757


$ clang++ -m64 -msse 32vs64.cpp --std=c++11 -O2
$ ./a.out
result = 49995000
Add 32 time in clocks 3017
result = 49995000
Add 64 time in clocks 9180
result = 349965000
Add Mul 32 time in clocks 11562
result = 349965000
Add Mul 64 time in clocks 16159
result = 7137858
Add Div 32 time in clocks 17523
result = 7137858
Add Div 64 time in clocks 47043
result = 49995000
Matrix 32 time in clocks 8622
result = 49995000
Matrix 64 time in clocks 12448


$ clang++ -m64 -mno-sse 32vs64.cpp --std=c++11 -O2
$ ./a.out
result = 49995000
Add 32 time in clocks 10221
result = 49995000
Add 64 time in clocks 11270
result = 349965000
Add Mul 32 time in clocks 18342
result = 349965000
Add Mul 64 time in clocks 17693
result = 7137858
Add Div 32 time in clocks 47695
result = 7137858
Add Div 64 time in clocks 52875
result = 49995000
Matrix 32 time in clocks 15811
result = 49995000
Matrix 64 time in clocks 15168
 45
Author: Mats Petersson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-10 00:56:08

[15]}więcej niż kiedykolwiek chciałeś wiedzieć o robieniu 64-bitowej matematyki w trybie 32-bitowym...

Gdy używasz 64-bitowych liczb w trybie 32-bitowym (nawet na 64-bitowym procesorze, jeśli kod jest skompilowany dla 32-bitów), są one przechowywane jako dwie oddzielne 32-bitowe liczby, jedna przechowuje wyższe bity liczby, a druga niższe bity. Wpływ tego zależy od instrukcji. (tl; dr-generalnie Robienie 64-bitowej matematyki na 32-bitowym CPU jest w teorii 2 razy wolniejsze, o ile nie dzielisz / modulo, jednak w praktyce różnica będzie mniejsza (moim zdaniem 1.3 x), ponieważ zwykle programy nie tylko robią matematykę na 64-bitowych liczbach całkowitych, a także ze względu na pipelining, różnica może być znacznie mniejsza w twoim programie).

Dodawanie/odejmowanie

Wiele architektur obsługuje tak zwane niosące flagę . Jest ustawiany, gdy wynik przepełnienia dodawania lub wynik odejmowania nie jest zaniżony. Zachowanie tych bitów może być pokazane Z Długim dodawaniem i długim odejmowaniem. C w ten przykład pokazuje albo bit wyższy niż najwyższy reprezentowalny bit (podczas operacji), albo flagę carry (po operacji).

  C 7 6 5 4 3 2 1 0      C 7 6 5 4 3 2 1 0
  0 1 1 1 1 1 1 1 1      1 0 0 0 0 0 0 0 0
+   0 0 0 0 0 0 0 1    -   0 0 0 0 0 0 0 1
= 1 0 0 0 0 0 0 0 0    = 0 1 1 1 1 1 1 1 1

Dlaczego carry flag ma znaczenie? Tak się składa, że procesory mają zwykle dwie oddzielne operacje dodawania i odejmowania. W x86 operacje dodawania nazywa się add i adc. add oznacza dodawanie, natomiast {[2] } oznacza dodawanie z przenoszeniem. Różnica między nimi polega na tym, że adc rozważa bit carry, a jeśli jest ustawiony, dodaje go do wynik.

Podobnie, odejmowanie z carry odejmuje 1 od wyniku, jeśli bit carry nie jest ustawiony.

To zachowanie pozwala łatwo zaimplementować dowolne dodawanie i odejmowanie wielkości na liczbach całkowitych. Wynik dodawania xi y (zakładając, że są to 8-bitowe) nigdy nie jest większy niż 0x1FE. Jeśli dodasz 1, otrzymasz 0x1FF. 9 bitów wystarcza więc do reprezentowania wyników dowolnego dodawania 8-bitowego. Jeśli rozpoczniesz dodawanie od add, a następnie dodasz dowolne bity oprócz początkowych z adc, możesz dodawać dane o dowolnym rozmiarze.

Dodanie dwóch 64-bitowych wartości na 32-bitowym procesorze wygląda następująco.

  1. Dodaj pierwsze 32 Bity b do pierwszych 32 bitów a .
  2. dodaj Z carry później 32 Bity b później 32 Bity a .

Analogicznie do odejmowania.

Daje to 2 instrukcje, jednak z powodu instrukcji pipelinining, to może być wolniejszy, ponieważ jedno obliczenie zależy od drugiego, więc jeśli CPU nie ma nic innego do zrobienia niż 64-bitowe dodawanie, CPU może poczekać na pierwsze dodanie.

Mnożenie

Tak się dzieje na x86, że imul i mul mogą być używane w taki sposób, że przepełnienie jest przechowywane w EDX rejestrze. Dlatego mnożenie dwóch wartości 32-bitowych w celu uzyskania wartości 64-bitowej jest naprawdę łatwe. Takie mnożenie jest jedną instrukcją, ale aby z niej skorzystać, jedna z wartości mnożenia musi być przechowywana w eax .

W każdym razie, dla bardziej ogólnego przypadku mnożenia dwóch wartości 64-bitowych, można je obliczyć za pomocą następującego wzoru (Załóżmy, że funkcja r usuwa bity powyżej 32 bitów).

Po pierwsze, łatwo zauważyć, że niższe 32 bity wyniku będzie mnożeniem niższych 32 bitów mnożonych zmiennych. Wynika to z relacji zbieżności.

a1b1 (mod n)
a2b2 (mod n)
a1a2b1b2 (mod n)

Dlatego zadanie ogranicza się tylko do określenia wyższych 32 bitów. Aby obliczyć wyższe 32 bity wyniku, należy dodać następujące wartości.

  • wyższe 32 bity mnożenia obu niższych 32 bity (przepełnienie, które procesor może przechowywać w edx)
  • wyższe 32 bity pierwszej zmiennej mulitplied z niższymi 32 bity drugiej zmiennej
  • niższe 32 bity pierwszej zmiennej pomnożone przez wyższe 32 bity drugiej zmiennej

Daje to około 5 instrukcji, jednak ze względu na stosunkowo ograniczoną liczbę rejestrów w x86 (ignorując rozszerzenia architektury), nie mogą one zbytnio korzystać z pipeliningu. Włącz SSE, jeśli chcesz poprawić prędkość mnożenia, gdyż zwiększa to liczbę rejestrów.

Division / Modulo (oba są podobne w implementacji)

Nie wiem, jak to działa, ale jest znacznie bardziej złożone niż dodawanie, odejmowanie czy nawet mnożenie. Prawdopodobnie będzie dziesięć razy wolniejszy niż division na 64-bitowym procesorze. Sprawdź "Art of Computer Programming, Volume 2: Seminumerical Algorithms", strona 257, aby uzyskać więcej szczegółów, jeśli możesz to zrozumieć (nie mogę tego wyjaśnić w sposób, w jaki mogę to wyjaśnić, niestety).

Jeśli dzielisz przez potęgę 2, zapoznaj się z sekcją przesunięcia, ponieważ na to zasadniczo kompilator może zoptymalizować dzielenie (plus dodanie najważniejszego bitu przed przesunięciem dla liczb podpisanych).

Lub / I / Xor

Biorąc pod uwagę, że operacje te są operacjami jednobitowymi, nic specjalnego się tu nie dzieje, tylko operacja bitowa jest wykonywana dwa razy.

Przesunięcie w lewo / w prawo

Co ciekawe, x86 faktycznie ma instrukcję do wykonuje 64-bitowe przesunięcie w lewo o nazwie shld, które zamiast zastępować najmniej znaczące bity wartości zerami, zastępuje je najbardziej znaczącymi bitami innego rejestru. Podobnie jest w przypadku prawego przesunięcia z shrd instrukcją. To z łatwością sprawiłoby, że 64-bitowa zmiana byłaby operacją dwóch instrukcji.

To jednak tylko przypadek ciągłych zmian. Gdy zmiana nie jest stała, robi się coraz trudniej, ponieważ architektura x86 obsługuje tylko zmianę z wartością 0-31. Wszystko poza tym jest według oficjalnej dokumentacji undefined, a w praktyce bitowe i operacja z 0x1F jest wykonywana na wartości. Dlatego, gdy wartość przesunięcia jest wyższa niż 31, jeden z magazynów wartości jest usuwany całkowicie (dla lewego przesunięcia, to jest niższe bajty, dla prawego przesunięcia, to jest wyższe bajty). Drugi otrzymuje wartość, która była w rejestrze, który został skasowany, a następnie wykonywana jest operacja shift. To w rezultacie, zależy od Branch predictor zrobić dobre prognozy, i jest trochę wolniej, ponieważ trzeba sprawdzić wartość.

_ _ builtin _ popcount [ll]

__builtin _ popcount (lower) + _ _ builtin _ popcount (higher)

Inne budowle

Jestem zbyt leniwy, aby zakończyć odpowiedź w tym momencie. Czy ktoś w ogóle ich używa?

Unsigned vs signed

Dodawanie, odejmowanie, mnożenie, or, I, xor, shift w lewo generują dokładnie ten sam kod. Shift right używa tylko nieco innego kodu (przesunięcie arytmetyczne vs przesunięcie logiczne), ale strukturalnie jest tak samo. Jest jednak prawdopodobne, że division generuje inny kod, a signed division prawdopodobnie będzie wolniejszy niż unsigned division.

Benchmarki

Benchmarki? Są one w większości bez znaczenia, jak instrukcja pipelining zazwyczaj prowadzi do rzeczy jest szybsze, gdy nie stale powtarzają tę samą operację. Możesz uważać podział za powolny, ale nic innego tak naprawdę nie jest, a kiedy wyjdziesz poza benchmarki, możesz to zauważyć, ponieważ pipelining, wykonywanie 64-bitowych operacji na 32-bitowym procesorze wcale nie jest wolne.

Nie ufaj mikro-benchmarkom, które nie robią tego, co Twoja aplikacja. Nowoczesne procesory są dość skomplikowane, więc niepowiązane benchmarki mogą i będą kłamać.
 8
Author: Konrad Borowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-13 06:55:33

Twoje pytanie brzmi dość dziwnie w swoim otoczeniu. Używasz time_t, który używa do 32 bitów. Potrzebujesz dodatkowych informacji, co oznacza więcej bitów. Więc jesteś zmuszony użyć czegoś większego niż int32. Nie ma znaczenia jaki jest występ, prawda? Wybory pójdą między użyciem just say 40 bitów lub przejdź do int64. O ile nie ma konieczności przechowywania milionów instancji, to ten ostatni jest rozsądnym wyborem.

Jak zauważyli inni, jedynym sposobem na poznanie prawdziwej wydajności jest zmierzenie jej z profilerem (w niektórych grubych próbkach wystarczy prosty zegar). więc śmiało, zmierz. Nie może być trudno przypisać użycie time_t do typedef i przedefiniować go do 64 bitów i łatać kilka przypadków, w których oczekiwano rzeczywistego time_t.

Postawiłbym na "niezmierzoną różnicę", chyba że Twoje obecne instancje time_t zajmą przynajmniej kilka megów pamięci. na obecnych platformach podobnych do Intela rdzenie spędzają większość czasu czekając na dostęp pamięci zewnętrznej do pamięci podręcznej. A single Cache miss strains for hundred (s) of cycles. Co sprawia, że obliczanie różnic 1-tick na instrukcjach jest niewykonalne. Twoja prawdziwa wydajność może spaść z powodu rzeczy takich jak bieżąca struktura po prostu pasuje do linii pamięci podręcznej, a większa potrzebuje dwóch. A jeśli nigdy nie mierzyłeś swojej bieżącej wydajności, możesz odkryć, że możesz uzyskać ekstremalne przyspieszenie niektórych funkcji, dodając wyrównanie lub kolejność wymiany niektórych członków w strukturze. Lub pack (1) Struktura zamiast używać domyślny układ...

 2
Author: Balog Pal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-30 19:35:45

Dodawanie / odejmowanie w zasadzie staje się dwoma cyklami każdy, mnożenie i dzielenie zależy od rzeczywistego procesora. Ogólny wpływ na wydajność będzie raczej niski.

Zauważ, że Intel Core 2 obsługuje EM64T.

 0
Author: dom0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-30 16:30:15