Cortex-A15 vs Jaguar

Nexus10 は Cortex A15 のために買ったはずが全然何も調べてないなと思ってそういえばTemashも出たことだしたまには比較しようと思った。

環境

Cortex A15(以下A15) Jaguar Haswell(参考)
Exynos 5250 a4-1250 i7-4700MQ
コア数 2 2 4C8T
クロック 1.7 1.0 2.4

CPU 消費電力目安

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

static void *
loop(void *p)
{
    volatile float x= 0;
    volatile int y = 0;
    while (1) {
        x++;
        y++;
    }
}

int main(int argc, char **argv) {
    int nthread = 2;
    int i;
    pthread_t *threads;

    if (argc > 1) {
        nthread = atoi(argv[1]);
    }

    threads = malloc(sizeof(pthread_t) * nthread);

    for (i=0; i<nthread-1; i++) {
        pthread_create(&threads[i], NULL,
                       loop, NULL);
    }

    while (1);
}

こういうのを回してアイドル時と実行時の消費電力の差分

A15 Jaguar
アイドル時[W] 2 8
実行時[W] 7 12
消費電力かも[W] 5 4

CPUの消費電力って定義が難しいのでこの数値を持ってうんぬんは言えないと思うが、まあいい勝負してると言える。

SBU

SBU(http://www.linuxfromscratch.org/~bdubbs/about.html : make install含んでないが…)

Cortex-A15のほうがはやい。へー。binutilsアーキテクチャごとにコンパイルするソース違うので公平ではないが…

# 全部 make -j2 です
i7-4700MQ:
real    0m52.016s
user    1m8.163s
sys     0m15.614s

a4-1250 (Jaguar 1.0GHz x 2コア):
real    4m30.359s
user    6m41.989s
sys     0m48.279s

exynos5250 (Cortex-A15 1.7GHz x 2コア):
real    3m22.788s
user    4m27.405s
sys     0m38.650s

SunSpider

A15

Jaguar

なんか大体一緒ではという感想を持ちそうになるな。

いちおうグラフ

とくに検証もしないでベンチとってグラフ書くだけとかアレな感想風味が強いな。

まあJavaScriptとかJITの完成度の違いの影響を受けてそう。

Haswell

はやい

cairo

cairoって単純なのだとSIMDっぽい演算で複雑だとジオメトリックな演算(て何?)律速になるから、パラメータ変えるだけで色々ベンチマーク作れると思うんだよね。

#include <cairo.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int width, height;
cairo_surface_t *s0;
int nloop;

static double
usec()
{
    struct timeval tv;

    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000000.0 + tv.tv_usec;
}

typedef void (*bench_t) (void);

static void
clear()
{
    cairo_t *c = cairo_create(s0);

    cairo_set_source_rgb(c, 0, 0, 0);

    cairo_rectangle(c, 0, 0, width, height);
    cairo_fill(c);

    cairo_destroy(c);
}

static void
clear_alpha()
{
    cairo_t *c = cairo_create(s0);

    cairo_set_source_rgba(c, 0, 0, 1, 0.01);

    cairo_rectangle(c, 0, 0, width, height);
    cairo_fill(c);

    cairo_destroy(c);
}

static void
grad()
{
    cairo_t *c = cairo_create(s0);
    cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, height);

    cairo_pattern_add_color_stop_rgb(pat, 0, 1, 1, 1);
    cairo_pattern_add_color_stop_rgb(pat, 1, 0, 0, 0);

    cairo_set_source(c, pat);

    cairo_rectangle(c, 0, 0, width, height);
    cairo_fill(c);

    cairo_destroy(c);
    cairo_pattern_destroy(pat);
}

static void
moji()
{
    cairo_t *c = cairo_create(s0);
    cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, height);

    cairo_pattern_add_color_stop_rgb(pat, 0, 1, 1, 1);
    cairo_pattern_add_color_stop_rgb(pat, 1, 0, 0, 0);

    cairo_set_source(c, pat);
    cairo_move_to(c, 100, 100);
    cairo_rotate(c, 1.5);
    cairo_set_font_size(c, 32);
    cairo_set_line_width(c, 1.0);
    cairo_text_path(c, "abcdefghijklmnopqrstuvwxyz");

    cairo_stroke(c);

    cairo_destroy(c);
    cairo_pattern_destroy(pat);
}

static void
curve()
{
    cairo_t *c = cairo_create(s0);
    cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, height);
    int i;

    cairo_pattern_add_color_stop_rgb(pat, 0, 1, 1, 1);
    cairo_pattern_add_color_stop_rgb(pat, 1, 0, 0, 0);

    cairo_move_to(c, 100, 100);

    for (i=0; i<8; i++) {
        cairo_curve_to(c,
                       125+i*100, 100,
                       125+i*100, 1000,
                       150+i*100, 1000
            );

        cairo_curve_to(c,
                       175+i*100, 1000,
                       175+i*100, 100,
                       200+i*100, 100
            );
    }

    cairo_stroke(c);

    cairo_destroy(c);
    cairo_pattern_destroy(pat);
}


static void
run(bench_t b)
{
    double tb, te;
    int i;

    b();

    tb = usec();
    for (i=0; i<nloop; i++) {
        b();
    }
    te = usec();

    printf("%f\n", (te-tb)/nloop);
}

int
main(int argc, char **argv)
{
    int t = 0;
    int opt;

    width = 1024;
    height = 1024;
    nloop = 1000;

    while ((opt = getopt(argc, argv, "i:t:")) != -1) {
        switch (opt) {
        case 't':
            t = atoi(optarg);
            break;

        case 'i':
            nloop = atoi(optarg);
            break;

        default:
            puts("usage run -i nloop -t type");
            return 1;
        }
    }

    s0 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);

    switch (t) {
    case 0:
	run(clear);
	break;
    case 1:
	run(grad);
	break;
    case 2:
	run(moji);
	break;
    case 3:
        run(curve);
        break;
    case 4:
        run(clear_alpha);
        break;

    }

    if (1) {
        cairo_surface_write_to_png(s0, "out.png");
    }

    return 0;
}
Jaguar
$ ./run-x86 -t 0 -i 128 # fillするだけ
1729.984375
$ ./run-x86 -t 1 -i 4   # グラデfill
55545.750000
$ ./run-x86 -t 2 -i 16  # font
36090.875000
$ ./run-x86 -t 3 -i 16  # curve
7033.187500
$ ./run-x86 -t 4 -i 16  # alpha fill
3071.437500

A15
# ./run -t 0 -i 128
721.210938
# ./run -t 1 -i 4
85699.000000
# ./run -t 2 -i 16
37483.875000
# ./run -t 3 -i 16
5625.562500
# ./run -t 4 -i 16
2835.687500

これちょっと真面目に調べるから待って。

himenoBMT

まあコードあってすぐ数字出るやつもう一個ぐらい出しとくか

jaguar
$ ./bmt 
mimax = 257 mjmax = 129 mkmax = 129
imax = 256 jmax = 128 kmax =128
cpu : 44.229731 sec.
Loop executed for 200 times
Gosa : 1.245715e-03 
MFLOPS measured : 619.968211
Score based on MMX Pentium 200MHz : 19.211906

a15
# ./bmt
mimax = 257 mjmax = 129 mkmax = 129
imax = 256 jmax = 128 kmax =128
cpu : 47.590516 sec.
Loop executed for 200 times
Gosa : 1.245715e-03 
MFLOPS measured : 576.186802
Score based on MMX Pentium 200MHz : 17.855184

haswell
$ ./bmt 
mimax = 257 mjmax = 129 mkmax = 129
imax = 256 jmax = 128 kmax =128
cpu : 8.620606 sec.
Loop executed for 200 times
Gosa : 1.245715e-03 
MFLOPS measured : 3180.870022
Score based on MMX Pentium 200MHz : 98.570500

気が向いたら真面目に調べるかも。

cairo 解析 -t 0

fillしてるだけ

A15 Jaguar
721.210938 1729.984375
         :        extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
         :        _mm_store_si128 (__m128i *__P, __m128i __B)
         :        {
         :          *__P = __B;
    1.49 :           73863:       movdqa %xmm0,(%rdx)
    0.00 :           73867:       movdqa %xmm0,0x10(%rdx)
    2.49 :           7386c:       movdqa %xmm0,0x20(%rdx)
    9.95 :           73871:       movdqa %xmm0,0x30(%rdx)
   40.30 :           73876:       movdqa %xmm0,0x40(%rdx)
    1.00 :           7387b:       movdqa %xmm0,0x50(%rdx)
    6.47 :           73880:       movdqa %xmm0,0x60(%rdx)
    6.47 :           73885:       movdqa %xmm0,0x70(%rdx)
         :                    save_128_aligned ((__m128i*)(d + 64),  xmm_def);
         :                    save_128_aligned ((__m128i*)(d + 80),  xmm_def);
         :                    save_128_aligned ((__m128i*)(d + 96),  xmm_def);
         :                    save_128_aligned ((__m128i*)(d + 112), xmm_def);   

まあこれが遅い。


なんか

http://en.wikipedia.org/wiki/Exynos_%28system_on_chip%29 : Dual Channel らしい

http://northwood.blog60.fc2.com/blog-entry-6827.html : single channel らしい

という違いが出てる気がする。いや倍以上違ってね?まあ伝統的にAMDのメモコンは理論値の3-4割ぐらいしか出ないからな…あとで実測しよう。

cairo 解析 -t 3

static void
clear_alpha()
{
    cairo_t *c = cairo_create(s0);

    cairo_set_source_rgba(c, 0, 0, 1, 0.01);

    cairo_rectangle(c, 0, 0, width, height);
    cairo_fill(c);

    cairo_destroy(c);
}
A15 Jaguar
5625.562500 7033.187500

sse2_composite_over_n_8888 が遅い。

ARMのはなんかperfがうまく動かなくて取れないがまあ一緒だとしたら neon_composite_over_n_8888かな…これasm手書きか…というかソフトウェアパイプライニングしてるように見えるな。

まあわかった。 (わかってない。あんま信頼性無いので信用しないように)

A15 の実装は、32byteで

    vmull.u8    q8, d24, d4
    vmull.u8    q9, d24, d5
    vmull.u8    q10, d24, d6
    vmull.u8    q11, d24, d7
    vrshr.u16   q14, q8, #8
    vrshr.u16   q15, q9, #8
    vrshr.u16   q2, q10, #8
    vrshr.u16   q3, q11, #8
    vraddhn.u16 d28, q14, q8
    vraddhn.u16 d29, q15, q9
    vraddhn.u16 d30, q2, q10
    vraddhn.u16 d31, q3, q11
    vqadd.u8    q14, q0, q14
    vqadd.u8    q15, q1, q15

x86の実装は、16byteで、

	movdqu		(%rdx),%xmm0
	sub		$0x4,%esi
	movdqa		%xmm0,%xmm1
	punpckhbw	%xmm2,%xmm0
	punpcklbw	%xmm2,%xmm1
	pmullw		%xmm13,%xmm0
	paddusw		%xmm5,%xmm0
	pmulhuw		%xmm4,%xmm0
	pmullw		%xmm13,%xmm1
	paddusb		%xmm3,%xmm0
	paddusw		%xmm5,%xmm1
	pmulhuw		%xmm4,%xmm1
	paddusb		%xmm3,%xmm1
	packuswb	%xmm0,%xmm1
	movdqa		%xmm1,(%rdx)

こうか。なんかもっとA15のほう速くなってよさそうだよな。


まあNEON読めるようにならないといかんともしがたい。(前後のvzip/vuzpが何やってるかわからないと…)

うーんだめだなまた来週続き。(多分続かない)